透明,非侵入性的实时文件复制

时间:2015-12-14 06:17:04

标签: windows filesystems

我们有一个长期运行的旧Windows应用程序,由于各种原因无法更新。该程序以不可预测的间隔写出数据文件。在写出新数据文件之前,它首先重命名以前的数据文件。

其他应用程序(好吧,至少有一个!)需要实时访问最新的数据文件。问题是如果读取器程序在编写器程序尝试重命名时打开文件,则编写器程序崩溃。这绝不可能发生!

解决编写程序的明显解决方案是不切实际的。我想要找到的是一些Windows服务或替代文件系统,它们可以在写入时透明地复制文件。通过这种方式,读者程序可以访问复制的文件而不会干扰编写器程序(如果读取器程序出现错误,则更为重要)。

据我所知,磁盘镜像无法解决我们的文件锁定问题。

我的问题:有没有人知道我们可以使用这样的服务?

编辑:说明问题的示例代码,即使假定非锁定文件读取:

const string SrcFilePath = @"C:\Foo.txt";
const string DestFilePath = @"C:\Bar.txt";

void Main()
{
    Task.Run(() =>
    {
        while (true)
        {
            try
            {
                Console.WriteLine("Writer: moving {0} to {1}", SrcFilePath, DestFilePath);
                File.Move(SrcFilePath, DestFilePath);
                Console.WriteLine("Writer: writing {0}", SrcFilePath);
                File.WriteAllText(SrcFilePath, "Hello, World!\n");
            }
            catch (Exception e)
            {
                Console.WriteLine("Writer: error: {0}", e.Message);
            }
            Console.WriteLine("Writer: sleeping.");
            Task.Delay(1000).Wait();
        }
    });
    Task.Run(() =>
    {
        while (true)
            try
            {
                Console.WriteLine("Reader: opening {0}", SrcFilePath);
                var fs = new FileStream(SrcFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                Console.WriteLine("Reader: sleeping...");
                Task.Delay(1500).Wait(); // Simulate a context switch in the middle of a file read.
                Console.WriteLine("Reader: waking up.");
                Console.WriteLine("Reader: closing {0}", SrcFilePath);
                fs.Dispose();
            }
            catch (Exception e)
            {
                Console.WriteLine("Reader: error: {0}", e.Message);
            }
    });
}

这样就失败了:

Reader: opening C:\Foo.txt
Reader: sleeping...
Writer: moving C:\Foo.txt to C:\Bar.txt
Writer: error: The process cannot access the file because it is being used by another process.
Writer: sleeping.
Reader: waking up.
Reader: closing C:\Foo.txt

2 个答案:

答案 0 :(得分:0)

要移动文件,共享模式必须允许您删除它。在这种情况下,这意味着FileShare.Delete选项。

答案 1 :(得分:0)

NTFS有一个名为“卷影复制”的有趣功能,可让您在使用硬盘时拍摄硬盘的快照。当其他应用程序写入HDD时,这些更改将存储在另一个HDD扇区中,而卷影副本仍将包含创建卷影副本时的数据。你的主要缺点是 - 他们初始化的速度相对较慢,如果“实时”你的意思是你需要每秒查询一次数据,那么恐怕这种方法对你不起作用。然而,这是最可靠和最不分散注意力的方式。 Here’s some guide

另一种可能适合您的方法。每次您想要阅读数据时:

  • 暂停编写程序进程。 There’re several ways
  • 查找最新的数据文件
  • 调用CreateHardLink API将该最新数据文件链接到同一NTFS卷上的其他路径。
  • 恢复编写程序。
  • 现在阅读使用备用路径打开它的最新文件。

这样,即使您使用备用路径读取相同的数据,编写器进程也应该能够正确地重命名文件。