这些.tmp文件是从哪里来的
Where did these .tmp files come from?
首先,一些细节:
- 我使用的是C++(Armadillo库)和R的组合
- 我使用Ubuntu作为我的操作系统
- 我不是使用Rcpp
假设我有一些名为cpp_code的C++代码,它是:
- 从R读取一个整数作为输入
- 执行一些计算
- 将电子表格"out.csv"保存为R的输出。(我使用.save(name,file_type=csv))
一些简化的R代码是:
for(i in 1:10000)
{
system(paste0("echo ", toString(i), " | ./cpp_code")) ## produces out.csv
output[i,,] <- read.csv("out.csv") ## reads out.csv
}
我的问题:
99%的时候,一切都很好。然而,我时不时地会收到一些不寻常的.tmp文件,比如:"out.csv.tmp_a0ac9806ff7f0000703a"。这些.tmp文件只出现一秒钟左右,然后突然消失了。
问题:
- 是什么原因造成的
- 有没有办法阻止这种情况的发生
请对我宽容一点,因为计算机不是我的主要学科。
非常感谢您抽出时间。
许多程序将输出写入临时文件,然后将其重命名为目标文件。这样做通常是为了避免在写入过程中进程被终止时留下半写的输出文件。通过使用临时文件,可以将文件原子地重命名为输出文件名,从而确保:
- 整个输出文件已正确写入或
- 输出文件没有更改
请注意,通常仍然存在一些竞争条件,例如,输出文件被删除,但临时文件没有被重命名,但以上两种结果之一是总体目标。
我相信您在armadillo
中使用.save
函数。
http://arma.sourceforge.net/docs.html#save_load_field
您应该在中看到两个函数include/armadillo_bits/diskio_meat.hpp
。在save_raw_ascii
中,它首先将数据存储到diskio::gen_tmp_name
的文件名中,如果是save_okay
,则按safe_rename
重命名。如果safe_okay
或safe_rename
失败,您将看到临时文件。临时文件名选择为filename + .tmp_ + some hex value from file name
。
//! Save a matrix as raw text (no header, human readable).
//! Matrices can be loaded in Matlab and Octave, as long as they don't have complex elements.
template<typename eT>
inline
bool
diskio::save_raw_ascii(const Mat<eT>& x, const std::string& final_name)
{
arma_extra_debug_sigprint();
const std::string tmp_name = diskio::gen_tmp_name(final_name);
std::fstream f(tmp_name.c_str(), std::fstream::out);
bool save_okay = f.is_open();
if(save_okay == true)
{
save_okay = diskio::save_raw_ascii(x, f);
f.flush();
f.close();
if(save_okay == true)
{
save_okay = diskio::safe_rename(tmp_name, final_name);
}
}
return save_okay;
}
//! Append a quasi-random string to the given filename.
//! The rand() function is deliberately not used,
//! as rand() has an internal state that changes
//! from call to call. Such states should not be
//! modified in scientific applications, where the
//! results should be reproducable and not affected
//! by saving data.
inline
std::string
diskio::gen_tmp_name(const std::string& x)
{
const std::string* ptr_x = &x;
const u8* ptr_ptr_x = reinterpret_cast<const u8*>(&ptr_x);
const char* extra = ".tmp_";
const uword extra_size = 5;
const uword tmp_size = 2*sizeof(u8*) + 2*2;
char tmp[tmp_size];
uword char_count = 0;
for(uword i=0; i<sizeof(u8*); ++i)
{
conv_to_hex(&tmp[char_count], ptr_ptr_x[i]);
char_count += 2;
}
const uword x_size = static_cast<uword>(x.size());
u8 sum = 0;
for(uword i=0; i<x_size; ++i)
{
sum += u8(x[i]);
}
conv_to_hex(&tmp[char_count], sum);
char_count += 2;
conv_to_hex(&tmp[char_count], u8(x_size));
std::string out;
out.resize(x_size + extra_size + tmp_size);
for(uword i=0; i<x_size; ++i)
{
out[i] = x[i];
}
for(uword i=0; i<extra_size; ++i)
{
out[x_size + i] = extra[i];
}
for(uword i=0; i<tmp_size; ++i)
{
out[x_size + extra_size + i] = tmp[i];
}
return out;
}
"Dark Falcon"的假设完全正确:当调用save
时,Armadillo会创建一个临时文件来保存数据,然后将文件重命名为最终名称。
这可以在源代码中看到(这是save_raw_ascii
,但其他save*
函数的工作方式类似):
const std::string tmp_name = diskio::gen_tmp_name(final_name);
std::fstream f(tmp_name.c_str(), std::fstream::out);
bool save_okay = f.is_open();
if(save_okay == true)
{
save_okay = diskio::save_raw_ascii(x, f);
f.flush();
f.close();
if(save_okay == true)
{
save_okay = diskio::safe_rename(tmp_name, final_name);
}
}
关于safe_rename
的评论是这样说的:
安全地重命名文件。在重命名之前,测试我们是否可以写入最终文件。这应该可以防止:
- 覆盖写保护的文件
- 覆盖目录
值得注意的是,这不会阻止比赛条件。
- .cpp和.h文件中的模板专用化声明
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 文本文件中的单词链表
- CMake-按正确顺序将项目与C运行时对象文件链接
- 使用新行和不使用新行读取文件
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 挂起和取消挂起一个文件DLL
- 如何确定我已使用非编码文件到达 EOF?
- 命名空间中具有.h和.cpp文件的类
- 如何使用ndk-build.cmd构建Android.so文件
- 从包含m行的文件中提取n行,必要时(惰性地)重复该文件
- 读取文件并输入到矢量中
- 在C++中查找文件
- c++库的公共头文件中应该包含什么
- 用c++从输入文件中读取另一行
- Cppcheck生成xml转储文件
- 读取文件的最后一行并输入到链接列表时出错
- 似乎无法通过线路读取TMP文件
- Doxygen 错误:无法打开临时文件 /path/to/file/doxygen_objdb_3332.tmp
- 这些.tmp文件是从哪里来的