【问题标题】:How to write a file that is being read?如何编写正在读取的文件?
【发布时间】:2012-04-02 20:04:10
【问题描述】:

我的应用程序缓慢地读取浮点数的 TextFile。有时情况会发生变化,必须重写文件。一些示例代码:

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

【问题讨论】:

  • 使您的阅读程序对不完整的阅读具有鲁棒性。然后使用现代 IO(即TFileStream)而不是 Pascal IO。当您打开文件时,请为您的作者指定fmShareDenyWrite。为您的读者指定fmShareDenyNone。或者,使用数据库!
  • 我描述的情况是一个导入工具,所以我使用 csv-files。数据库可以解决所有问题,但在这种情况下是不可行的。

标签: delphi file-io


【解决方案1】:

要写入一个也可以读取的文件,通常不需要编写器执行任何特殊操作。如果打开文件的其他人都允许写入文件,那么预期的写入者可以打开文件进行写入,写入文件,然后关闭它。如果其他人没有允许写入文件,那么预期的写入者首先将不被允许打开文件,并且它无能为力。

如何打开文件进行读取同时还允许写入取决于所使用的打开方法。对于CreateFiledwDesiredAccess 参数是通常的GENERIC_READdwShareMode 参数是FILE_SHARE_READ or FILE_SHARE_WRITE。如果您使用的是TFileStream,那么构造函数的mode 参数应该是fmOpenWrite or fmShareDenyNone。如果你使用AssignFileReset,那么你需要设置FileMode 全局变量,但是它不支持任何共享模式,所以你不能使用Pascal 风格的I/O。

读取同时写入的文件不会导致崩溃。它当然不会在操作系统级别引起问题。如果您的程序崩溃,那是因为它不是为了预测读取失败而编写的。当您读取某些内容时,请检查 API 结果以确认您读取的字节数与请求的一样多。您还可以让读写应用程序相互通信。您可以使用同步对象来序列化对文件的访问,或者写入器可能会向读取器发送信号以指示文件已更改,并且先前的读取可能不再准确。细节由您决定。

如果阅读器要在内存中保留文件的副本,那么它可能不需要共享写访问权限。相反,它可以打开文件并仅共享读取权限,在内存中复制文件,然后关闭文件。然后作者可以打开文件,而不必担心会踩踏阅读器进程,因为没有什么可以踩踏的。它可以通知读者发生了一些变化,读者可以重新加载整个文件,也可以只加载发生变化的部分。 (不过,作者必须告诉读者哪个部分发生了变化;如果不阅读整个文件并查看它与内存副本有何不同,读者就无法检测到这一点。)

防止写入干扰读取的另一种方法是使用事务。不过,Transactional NTFS 正在逐步淘汰。 Microsoft 已发布a list of alternatives,因此您可以尝试找到符合您需求的内容。

【讨论】:

  • 非常感谢您的详尽回答。我认为它回答了我应该避免的所有陷阱。有一件事我还不知道,我怎么知道文件已经(重新)写入了?
  • 我应该更准确地表述问题 3。我的意思是我如何检测被另一个应用程序修改的文件。我将第 3 段视为在解释中检测变化的解释。如果有更多打算,我不知道该怎么办。
  • 这一直是我的假设:一个或多个进程正在读取,而另一个或多个进程正在写入。一个进程知道另一个进程修改了文件的可靠方法是让另一个进程告诉它已经这样做了;这就是我第三段的第二部分要表达的意思。您也可以尝试使用ReadDirectoryChangesW 来检测目录中的文件是否已更改大小或上次写入时间。
  • 非常感谢!您的回答使我从使用 TextFiles 更改为 Streams。这可以更好地控制文件打开的模式。关于“ReadDirectoryChangesW”的一个问题:写入文件时会触发多次:有什么方法可以确定哪个事件属于 Close 事件?另见stackoverflow.com/questions/10125444/…
猜你喜欢
  • 2019-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-03
  • 2010-09-05
  • 1970-01-01
  • 2019-07-10
相关资源
最近更新 更多