【问题标题】:Reopening a closed file stream重新打开关闭的文件流
【发布时间】:2016-10-10 17:58:56
【问题描述】:

考虑以下代码,

auto fin = ifstream("address", ios::binary);
if(fin.is_open()) 
    fin.close()
for(auto i = 0; i < N; ++i){
    fin.open()
    // ....
    // read (next) b bytes...
    // ....
    fin.close()
    // Some delay
}

上面的代码不能用我知道的C++实现,但我想知道是否可以这样做?

这是我的要求:

  • 重新打开文件时,无需再次传递参数(路径和模式)。
  • 重新打开流时,它会从流中关闭时的位置继续。

澄清

  • 我使用的文件很大,在某个时间点,来自第三方库的其他线程可能会决定(重新)移动它们。开放的流将阻止此类行为。
  • 连续读取大文件会降低系统速度。

【问题讨论】:

  • 流的工作方式并非如此。如果您希望它打开并定位,为什么要关闭它?
  • @BoPersson 我使用的文件很大,在某个时间点,来自第三方库的其他线程可能会决定删除它们。开放的流将阻止此操作,并且这些线程可能会失败。
  • 在这里为并发噩梦做好准备。建议重新考虑。
  • 删除了我的答案,因为我不记得足够多的 C++ 来继续回答。您总是可以创建一个接受构造函数参数的函数,并返回一个接受流的新函数,并在旧函数停止的地方创建一个新函数。可能是实现您想要实现的目标的最简单方法。
  • @Carcigenicate 感谢您抽出宝贵的时间来回答。谢谢你。我从你提到的内容中得到了一个想法。

标签: c++ c++11 visual-c++ c++14


【解决方案1】:

需要

确实,只要流保持打开状态,另一个进程就不能删除文件。

我想你已经问过自己这些问题了,但是对于记录者,我建议你考虑一下:

  • 不能将文件读入(虚拟)内存并在不再需要时丢弃吗?
  • 文件处理不能异步流水线,一次读取并处理它而没有不必要的延迟吗?
  • 如果文件因为被其他进程删除而无法再打开怎么办?如果由于文件被修改(例如缩短)而找不到位置怎么办?
  • 如果您有完美的解决方案来解决您的问题,如果其他进程在打开文件时尝试删除文件(只是一小段时间,但仍然打开并阻止删除),会产生什么影响?

解决方案

很遗憾,您无法使用标准流实现所需的行为。您可以通过跟踪文件名和位置(以及更普遍的状态)来模拟它:

   auto mypos = ifs.tellg();  // saves position.  
                              // Should flag be saved as well ? and what about gcount ?
   ifs.close();  

   ...

   if (! ifs.is_open()) {
       ifs.open(myfilename, myflags);  // open again !  
       if (! ifs) { 
           // ouch ! file disapeared ==> process error 
       }
       ifs.seekg(mypos);              // restore position 
       if (! ifs) { 
           // ouch ! position no longer reachable  ==> process error 
       }
   }

当然,您不希望永远重复此代码。突然有很多全局变量来跟踪流的状态并不是很好。但是您可以很容易地将它封装在一个包装类中,该类将使用现有的标准操作来保存和恢复流的状态。

【讨论】:

  • 即使文件打开了,它也可能被其他进程截断为零大小,并且它的目录条目可能会被删除。预期的操作系统是什么?
  • @HeikoBloch 是的,我们不会在这里解决 OP 的所有挑战。我认为 OP 由于“visual C++”标签而以窗口为目标
  • 谢谢。你问的问题,我都记在心里了。不幸的是,您提到的所有风险都存在,我没有比您给出的更好的解决方案。似乎没有其他或更好的解决方案。再次感谢您。