将Directory.GetFiles()或EnumerateFiles与包含锁定文件的目标目录一起使用的最佳实践?

时间:2013-02-26 11:55:53

标签: c# filesystems .net

目前我尝试改进两种Windows服务(C#)的设计。 服务A生成数据导出(csv文件)并将其写入临时目录。 因此,文件将写入作为子目录的临时目录。主输出目录。 然后将文件(通过 File.Move )移动到输出目录(成功写入后)。 此导出可以由多个线程执行。

另一个服务B尝试在定义的时间间隔内从此输出目录中获取文件。 如何确保 Directory.GetFiles() 排除锁定的文件。

  1. 我是否应该尝试通过创建新的FileStream来检查每个文件(使用 (Stream stream = new FileStream("MyFilename.txt", FileMode.Open))as 描述 here

  2. 或者生产者服务(A)是否应该使用临时文件名(* .csv.tmp)     消费者服务(B)自动排除适当的搜索模式。移动完成后重命名文件。

  3. 是否有更好的方法来处理此类文件列表操作。

2 个答案:

答案 0 :(得分:0)

一种方法是在使用时将文件标记为临时写入应用程序,并且只有在写入和关闭时才将其标记为未标记,例如。

FileStream f = File.Create (filename);
FileAttributes attr = File.GetAttributes (filename);
File.SetAttributes (filename, attr | FileAttributes.Temporary);
 //write to file.
f.Close ();

File.SetAttributes (filename, attr);

从消费应用中,您只想跳过任何临时文件。

foreach (var file in Directory.GetFiles (Path.GetDirectoryName (filename))) {
    if ((File.GetAttributes (file) & FileAttributes.Temporary) != 0) continue;
    // do normal stuff.
}

答案 1 :(得分:0)

不要打扰检查!

咦?怎么会这样?

如果文件在同一个驱动器上,则Move操作是原子的!该操作实际上是重命名,从前一个目录条目中删除,并将其插入到下一个目录中,指向数据实际所在的相同扇区(或whatevers),而不重写它。文件系统的内部锁定机制必须锁定&阻止目录在此过程中读取,以防止目录扫描返回损坏的结果。

这意味着,当它出现在目录中时,它将不会被锁定;实际上,自从将其写入上一个目录的关闭操作以来,该文件将不会被打开/修改。

警告 - (1)绝对不能在驱动器,分区或作为子目录安装的其他媒体之间工作。操作系统在后台执行复制+删除而不是目录条目编辑。 (2)这种行为是一种惯例,而不是一种规则。虽然我从来没有见过它,但是文件系统可以自由地打破它,甚至可以不一致地打破它!

所以这可能会奏效。如果没有,我建议使用你自己的临时扩展的想法(我之前已经完成了这个目的,但在客户端和服务器之间只能通过共享驱动器进行通信)并且它不是那样的努力工作,完美无缺。

如果你自己的想法太低技术,并且你在同一台机器上(听起来像你),你可以设置一个嵌入文件名的互斥锁(谷歌那个),当文件存在时写作,在作家过程中;然后在打开从其他进程读取的每个文件时对其执行阻止测试。如果您希望第二个进程响应ASAP将其与文件系统观察器结合起来。然后拍拍自己的背部,花费十倍的时间作为临时文件名的想法,没有额外的收益>: - }

祝你好运!