代码之家  ›  专栏  ›  技术社区  ›  Dmytro Leonenko

连续读取文件

  •  28
  • Dmytro Leonenko  · 技术社区  · 14 年前

    我想像GNU tail一样,用“-f”参数连续读取文件。我需要它来实时读取日志文件。

    7 回复  |  直到 14 年前
        1
  •  35
  •   Chris F Carroll    8 年前

    FileStream tail -f 作品。

    回答您的问题:

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

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

    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

    如果您想定期(例如每15秒)执行此操作,可以设置一个计时器来调用 ReadTail

        2
  •  37
  •   tsul    8 年前

    更自然的使用方法 FileSystemWatcher :

        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();
    

    文件系统监视程序 只是用来唤醒主要的阅读周期。

        3
  •  7
  •   Kind Contributor    7 年前

    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的可变字符长度。

    注意:您可以更改线程。睡眠部分是不同的计时,你也可以链接到一个filewatcher和阻塞模式-Monitor.Enter/等待/脉冲. 对我来说,计时器已经足够了,最多它只检查文件长度每秒钟,如果文件没有改变。

        4
  •  3
  •   Johann Medina    7 年前

    这是我的解决方案

        static IEnumerable<string> TailFrom(string file)
        {
            using (var reader = File.OpenText(file))
            {
                while (true) 
                {
                    string line = reader.ReadLine();
                    if (reader.BaseStream.Length < reader.BaseStream.Position) 
                        reader.BaseStream.Seek(0, SeekOrigin.Begin);
    
                    if (line != null) yield return line;
                    else Thread.Sleep(500);
                }
            }
        }
    

    所以,在你的代码里你可以

        foreach (string line in TailFrom(file)) 
        {
            Console.WriteLine($"line read= {line}");            
        }
    
        5
  •  2
  •   Darin Dimitrov    14 年前

    你可以用这个 FileSystemWatcher

        6
  •  0
  •   Zyberzero    10 年前
    private void button1_Click(object sender, EventArgs e)
    {
        if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
        {
            path = folderBrowserDialog.SelectedPath;
            fileSystemWatcher.Path = path;
    
            string[] str = Directory.GetFiles(path);
            string line;
            fs = new FileStream(str[0], FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            tr = new StreamReader(fs); 
    
            while ((line = tr.ReadLine()) != null)
            {
    
                listBox.Items.Add(line);
            }
    
    
        }
    }
    
    private void fileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
    {
        string line;
        line = tr.ReadLine();
        listBox.Items.Add(line);  
    }
    
        7
  •  -7
  •   Snak3byte    14 年前

    如果你只是想找一个工具来做这件事,那么检查一下免费版本的 Bare tail