在.NET中阅读文件内容的更改

11
在Linux中,很多进程间通信都是通过在一个进程向文件追加内容,再由另一个进程读取新内容来实现的。
我想在Windows/.NET中做同样的事情(使用普通IPC如管道太麻烦了)。我正在从Python进程向一个文件追加内容,并希望每当FileSystemWatcher报告事件时只读取更改内容,而不是每次都将整个文件内容读入内存(该文件将非常大)。
每个追加操作都会追加一行数据,以唯一递增的计数器(时间戳+键)开头,以换行符结尾。
2个回答

29
    using (FileStream fs = new FileStream
       (fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    {
        using (StreamReader sr = new StreamReader(fs))
        {
            while (someCondition)
            {
                while (!sr.EndOfStream)
                    ProcessLinr(sr.ReadLine());
                while (sr.EndOfStream)
                    Thread.Sleep(100);
                ProcessLinr(sr.ReadLine());            
            }
        }
    }

这将帮助你只读取新增的行


一个伟大的解决方案,短小而致命! - MaYaN

11

当您收到文件更改通知时,您可以存储最后读取操作的偏移量,并将文件定位到该偏移量。以下是一个示例:

主要方法:

public static void Main(string[] args)
{
    File.WriteAllLines("test.txt", new string[] { });

    new Thread(() => ReadFromFile()).Start();

    WriteToFile();
}

从文件中读取的方法:

private static void ReadFromFile()
{
    long offset = 0;

    FileSystemWatcher fsw = new FileSystemWatcher
    {
        Path = Environment.CurrentDirectory,
        Filter = "test.txt"
    };

    FileStream file = File.Open(
        "test.txt",
        FileMode.Open,
        FileAccess.Read,
        FileShare.Write);

    StreamReader reader = new StreamReader(file);
    while (true)
    {
        fsw.WaitForChanged(WatcherChangeTypes.Changed);

        file.Seek(offset, SeekOrigin.Begin);
        if (!reader.EndOfStream)
        {
            do
            {
                Console.WriteLine(reader.ReadLine());
            } while (!reader.EndOfStream);

            offset = file.Position;
        }
    }
}

写入文件方法:

private static void WriteToFile()
{
    for (int i = 0; i < 100; i++)
    {
        FileStream writeFile = File.Open(
            "test.txt",
            FileMode.Append,
            FileAccess.Write,
            FileShare.Read);

        using (FileStream file = writeFile)
        {
            using (StreamWriter sw = new StreamWriter(file))
            {
                sw.WriteLine(i);
                Thread.Sleep(100);
            }
        }
    }
}

在文件操作方面,我有点新手。seek()函数是将整个文件加载到内存中还是只加载从偏移量到偏移量+长度的部分? - jameszhao00
据我所知,搜索操作不会加载任何数据,只会将文件流定位到指定位置。在这种情况下,位置将是新数据开始的地方。 - João Angelo

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