这些.tmp文件来自哪里?

时间:2014-04-24 17:34:28

标签: c++ r armadillo

首先,一些细节:

  • 我使用的是C ++(Armadillo library)和R。
  • 的组合
  • 我使用的是Ubuntu作为我的操作系统。
  • 使用Rcpp

假设我有一些名为 cpp_code 的C ++代码:

一些简化的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文件只出现一秒左右,然后突然消失。

问题:

  • 造成这种情况的原因是什么?
  • 有没有办法阻止这种情况发生?

因为计算不是我的主要学科,所以请放轻松。

非常感谢你的时间。

3 个答案:

答案 0 :(得分:4)

许多程序将其输出写入临时文件,然后将其重命名为目标文件。这通常是为了避免在写入过程中杀死进程时留下半写输出文件。通过使用临时文件,可以将文件原子重命名为输出文件名,确保:

  • 正确写入整个输出文件或
  • 未对输出文件进行任何更改

请注意,通常仍会存在一些竞争条件,例如,输出文件被删除但临时文件未重命名,但上述两个结果中的一个是一般目标。

答案 1 :(得分:3)

我相信您在.save中使用armadillo功能。

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_okaysafe_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;
  }

答案 2 :(得分:0)

“黑暗猎鹰”假设是完全正确的:当调用save时,Armadillo会创建一个临时文件,保存数据,然后将文件重命名为最终名称。

可以看到in the source code(这是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的评论说明了这一点:

  

安全地重命名文件。   在重命名之前,请测试我们是否可以写入最终文件。   这应该阻止:

     
      
  1. 覆盖写保护的文件,
  2.   
  3. 覆盖目录。
  4.   

值得注意的是,这会阻止竞争条件。