如何编写一个正在被读取的文件?

4

我的应用程序缓慢地读取一个浮点数的文本文件。不时情况会发生变化,需要重写文件。以下是一些示例代码:

procedure TAMI_Column_Selector.read_continuously (file_name: string);
var infile: TextFile;
    f: Double;
begin
   AssignFile (infile, file_name);
   Reset (infile);
   try
      while not EOF (infile) do
      begin
         Read (infile, f);
         process (f); // this may take quite some time, seconds or even minutes
      end; // while
   finally
      CloseFile (infile);
   end; // try..finally
end; // read_continuously //

如何编写同时可读取的文件?具体来说:
  1. 如何编写同时可读取的文件?
  2. 如何防止应用程序在尝试读取正在被写入的文件时崩溃?
  3. 我的应用程序如何知道文件已被重写?
我认为,通过将文件读入内存并读取它们(是否有一个 TextFile 可以写入并从内存中读取?)可以解决前两个问题。然后仍然需要解决如何测试文件是否已被覆盖的问题。
您是否有任何(优雅的)解决此问题的方法?
先行致谢。
在 Windows 7 上使用 Delphi XE。

1
让你的读取程序能够处理不完整的读取。然后使用现代 IO(即TFileStream)而不是 Pascal IO。对于你的写入器,在打开文件时指定 fmShareDenyWrite。对于你的读取器,在打开文件时指定 fmShareDenyNone。或者,使用数据库! - David Heffernan
我描述的情况是一个导入设施,因此我使用csv文件。数据库可以解决所有问题,但在这种情况下不可行。 - Arnold
1个回答

4
要向一个同时开放读写的文件中写入内容,通常情况下,写入者不需要做什么特殊的事情。如果其他所有打开该文件的人都已经允许对文件进行写操作,那么预期的写入者可以打开该文件进行写操作并将其关闭。如果其他人没有允许对文件进行写操作,那么预期的写入者将无法首先打开该文件,也无能为力。
如何在打开文件进行读取的同时允许写入,取决于所使用的打开方式。对于CreateFiledwDesiredAccess参数通常为GENERIC_READ,而dwShareMode参数为FILE_SHARE_READ or FILE_SHARE_WRITE。如果使用TFileStream,则构造函数的mode参数应设置为fmOpenWrite or fmShareDenyNone。如果使用AssignFileReset,则需要设置FileMode全局变量,但这不支持任何共享模式,因此不能使用Pascal风格的I/O。
读取同时正在写入的文件不会本质上导致崩溃。这当然不会在操作系统层面引起问题。如果您的程序崩溃,那是因为它没有被编写成预期读取失败。在读取时,请检查API结果以确认您读取了请求的字节数。您还可以让读取和写入应用程序相互通信。您可以使用同步对象来序列化对文件的访问,或者写入器可以向读取器发送信号以指示文件已更改,并且先前的读取可能不再准确。具体细节由您决定。
如果读取器将在内存中保留文件副本,则可能不需要共享写访问权限。相反,它可以打开文件并仅共享读访问权限,在内存中复制文件,然后关闭文件。然后,写入器可以打开文件,而不必担心践踏读取进程,因为没有东西可践踏。它可以通知读取器有些东西已经改变,读取器可以重新加载整个文件或只加载更改的部分。(不过,写入器必须告诉读取器哪个部分发生了变化;否则,读取器无法检测到除了读取整个文件并查看其与内存副本的差异之外的任何内容。)
另一种避免写入干扰读取的方法是使用事务。然而,Transactional NTFS 正在逐步淘汰。微软已经发布了替代方案列表,因此您可以尝试找到符合您需求的东西。

非常感谢您详细的回答。我认为它回答了我应该避免的所有陷阱。但有一件事我还不知道,那就是如何知道文件已经被(重新)写入? - Arnold
我应该更准确地表达第三个问题。我的意思是如何检测另一个应用程序修改了文件。我认为第三段是关于在解释中检测更改的说明。如果有更多意图,我不确定该怎么做。 - Arnold
这一直是我的假设:一个或多个进程正在读取,而另一个或多个进程正在写入。进程确切知道另一个进程修改了文件的方法是让另一个进程告诉它已经完成了;这就是我第三段的第二部分所要表达的。您还可以尝试使用ReadDirectoryChangesW来检测目录中的文件是否更改了大小或最后写入时间。 - Rob Kennedy
非常感谢!您的回答使我从使用TextFiles转向了Streams。这样可以更好地控制文件打开的模式。关于ReadDirectoryChangesW,有一个问题:当写入文件时,它会触发多次,有没有办法确定哪个事件属于Close事件?另请参阅http://stackoverflow.com/questions/10125444/how-detect-the-correct-modification-of-a-file。 - Arnold

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接