首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >c#连续读取文件

c#连续读取文件
EN

Stack Overflow用户
提问于 2010-09-25 05:21:50
回答 7查看 33.2K关注 0票数 39

我想像GNU tail一样用"-f“参数连续读取文件。我需要它来实时读取日志文件。什么才是正确的方法呢?

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2010-09-25 05:28:16

您希望以二进制模式打开FileStream。定期查找到文件末尾减去1024字节(或其他任何字节),然后读取到末尾并输出。这就是tail -f的工作原理。

您的问题的答案:

二进制,因为如果您将其作为文本读取,则很难随机访问该文件。您必须自己完成二进制到文本的转换,但这并不困难。(见下文)

1024字节,因为这是一个非常方便的数字,应该可以处理10到15行文本。通常是这样。

以下是打开文件、读取最后1024字节并将其转换为文本的示例:

代码语言:javascript
复制
static void ReadTail(string filename)
{
    using (FileStream fs = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    {
        // Seek 1024 bytes from the end of the file
        fs.Seek(-1024, SeekOrigin.End);
        // read 1024 bytes
        byte[] bytes = new byte[1024];
        fs.Read(bytes, 0, 1024);
        // Convert bytes to string
        string s = Encoding.Default.GetString(bytes);
        // or string s = Encoding.UTF8.GetString(bytes);
        // and output to console
        Console.WriteLine(s);
    }
}

请注意,您必须使用FileShare.ReadWrite打开,因为您正在尝试读取当前由另一个进程打开以供写入的文件。

还要注意,我使用的是Encoding.Default,在美国/英语和大多数西欧语言中,它都是8位字符编码。如果文件是以其他编码(如UTF-8或其他Unicode编码)编写的,则字节可能无法正确转换为字符。如果您认为这将是一个问题,那么您必须通过确定编码来处理它。有关确定文件的文本编码的信息,请搜索堆栈溢出。

如果您希望定期执行此操作(例如,每15秒),则可以设置一个计时器,该计时器可以根据需要随时调用ReadTail方法。你可以通过在程序开始时只打开文件一次来优化它。那随你的便。

票数 39
EN

Stack Overflow用户

发布于 2014-07-28 18:57:53

使用FileSystemWatcher的更自然的方法

代码语言:javascript
复制
    var wh = new AutoResetEvent(false);
    var fsw = new FileSystemWatcher(".");
    fsw.Filter = "file-to-read";
    fsw.EnableRaisingEvents = true;
    fsw.Changed += (s,e) => wh.Set();

    var fs = new FileStream("file-to-read", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
    using (var sr = new StreamReader(fs))
    {
        var s = "";
        while (true)
        {
            s = sr.ReadLine();
            if (s != null)
                Console.WriteLine(s);
            else
                wh.WaitOne(1000);
        }
    }

    wh.Close();

在这里,主读周期停止等待传入的数据,FileSystemWatcher只是用来唤醒主读周期。

票数 38
EN

Stack Overflow用户

发布于 2017-02-28 07:03:33

要连续监控文件的尾部,您只需记住文件之前的长度。

代码语言:javascript
复制
public static void MonitorTailOfFile(string filePath)
{
    var initialFileSize = new FileInfo(filePath).Length;
    var lastReadLength = initialFileSize - 1024;
    if (lastReadLength < 0) lastReadLength = 0;

    while (true)
    {
        try
        {
            var fileSize = new FileInfo(filePath).Length;
            if (fileSize > lastReadLength)
            {
                using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                {
                    fs.Seek(lastReadLength, SeekOrigin.Begin);
                    var buffer = new byte[1024];

                    while (true)
                    {
                        var bytesRead = fs.Read(buffer, 0, buffer.Length);
                        lastReadLength += bytesRead;

                        if (bytesRead == 0)
                            break;

                        var text = ASCIIEncoding.ASCII.GetString(buffer, 0, bytesRead);

                        Console.Write(text);
                    }
                }
            }
        }
        catch { }

        Thread.Sleep(1000);
    }
}

我不得不使用ASCIIEncoding,因为这段代码不够智能,无法在缓冲区边界上处理可变字符长度的UTF8。

备注:您可以将Thread.Sleep部件更改为不同的计时,也可以将其与文件守护程序和阻塞模式监视器相链接。输入/等待/脉冲。对我来说,计时器就足够了,如果文件没有变化,它最多只能每秒检查一次文件长度。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3791103

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档