阅读文本文件的最后一行

Deb*_*aar 29 c#

我需要知道如何阅读文本文件的最后一行.我需要找到该行,然后将其处理成一个SQL数据库...我一直在阅读并搜索网络,但我正在努力找到正确的方法来做到这一点.即:

  1. 查找文件的最后一行.
  2. 处理最后一行文件.

我希望这是有道理的.

Jon*_*eet 65

有两种方式:简单和低效,或者非常复杂但有效.复杂的版本采用合理的编码.

除非你的文件是如此之大,你真的可以读不起这一切,我只是用:

var lastLine = File.ReadLines("file.txt").Last();
Run Code Online (Sandbox Code Playgroud)

请注意,这里使用File.ReadLines,不是 File.ReadAllLines.如果您使用的是.NET 3.5或更早版本,则需要使用File.ReadAllLines或编写自己的代码 - ReadAllLines将一次性将整个文件读入内存,然后对其进行ReadLines流式处理.

否则,复杂的方法是使用类似于此的代码.它尝试从文件末尾向后读取,处理诸如UTF-8多字节字符之类的恶意.这不愉快.

  • @dscarr:你错过了一个`using`指令:`using System.Linq;` (2认同)

Tim*_*ter 9

我想简单地合并File.ReadLines(path)Enumerable.Last:

String last = File.ReadLines(@"C:\file.txt").Last();
Run Code Online (Sandbox Code Playgroud)

它会对行进行流式处理,而不会将所有内容加载到内存中File.ReadAllLines.


juF*_*uFo 9

第一部分:

File.ReadAllLines(@"c:\some\path\file.txt").Last();
Run Code Online (Sandbox Code Playgroud)

要么

File.ReadLines(@"c:\some\path\file.txt").Last();
Run Code Online (Sandbox Code Playgroud)

ReadLines是首选.


jjx*_*tra 6

注意:所有这些代码均假定为 UTF-8。如果您需要支持使用双宽字符(例如 Unicode)的代码页,那么您需要在换行符之前和/或之后对字符添加额外的检查,以确保它确实是换行符。

这个问题的主要用例之一是抓取日志文件的末尾。不幸的是,当日志文件达到兆字节时,其他答案就会惨死。想象一下在一个小型单核 VPS 上运行每个呼叫的每条线路……哎呀。

UTF-8 的好处是,当您输入 '\n' 字符时,您不必担心任何相关字节,因为 UTF8-8 中高位清除的任何字节都只是一个 ASCII 字符。相当方便!

您可以使用“如何使用 C# 中的迭代器反向读取文本文件”中的解决方案,但请注意该代码相当复杂。如果您只需要一个简单的 UTF-8 行预告片,那么此解决方案将工作得非常好,即使在大型日志文件上也能表现出色。

如果您同时监视大量文件并使用 C# 中的 FileSystemWatcher 之类的东西,那么这种性能提升将非常重要。我在廉价的单CPU Linux VPS 上使用非常相似的代码来监控登录失败,并将 IP 地址放入我的 MIT 许可项目https://github.com/DigitalRuby/IPBan的防火墙中,使用https://github.com/ DigitalRuby/IPBan/blob/master/IPBanCore/Core/Utility/LogFileScanner.cs(一次处理多个新行)。

当您的 SSH 端口面向公众时,您会对 auth.log 的大小感到惊讶。如果您定期阅读数十甚至数百个文件,您会很高兴没有使用File.ReadAllLines().Last();

由于这只是一页代码,因此在简单和快速之间取得了很好的平衡。

C# 代码...

/// <summary>
/// Utility class to read last line from a utf-8 text file in a performance sensitive way. The code does not handle a case where more than one line is written at once.
/// </summary>
public static class UTF8FileUtilities
{
    /// <summary>
    /// Read the last line from the file. This method assumes that each write to the file will be terminated with a new line char ('\n')
    /// </summary>
    /// <param name="path">Path of the file to read</param>
    /// <returns>The last line or null if a line could not be read (empty file or partial line write in progress)</returns>
    /// <exception cref="Exception">Opening or reading from file fails</exception>
    public static string ReadLastLine(string path)
    {
        // open read only, we don't want any chance of writing data
        using (System.IO.Stream fs = System.IO.File.OpenRead(path))
        {
            // check for empty file
            if (fs.Length == 0)
            {
                return null;
            }

            // start at end of file
            fs.Position = fs.Length - 1;

            // the file must end with a '\n' char, if not a partial line write is in progress
            int byteFromFile = fs.ReadByte();
            if (byteFromFile != '\n')
            {
                // partial line write in progress, do not return the line yet
                return null;
            }

            // move back to the new line byte - the loop will decrement position again to get to the byte before it
            fs.Position--;

            // while we have not yet reached start of file, read bytes backwards until '\n' byte is hit
            while (fs.Position > 0)
            {
                fs.Position--;
                byteFromFile = fs.ReadByte();
                if (byteFromFile < 0)
                {
                    // the only way this should happen is if someone truncates the file out from underneath us while we are reading backwards
                    throw new System.IO.IOException("Error reading from file at " + path);
                }
                else if (byteFromFile == '\n')
                {
                    // we found the new line, break out, fs.Position is one after the '\n' char
                    break;
                }
                fs.Position--;
            }

            // fs.Position will be right after the '\n' char or position 0 if no '\n' char
            byte[] bytes = new System.IO.BinaryReader(fs).ReadBytes((int)(fs.Length - fs.Position));
            return System.Text.Encoding.UTF8.GetString(bytes);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

string m = "";
StreamReader r = new StreamReader("file_path");
while (r.EndOfStream == false)
{
    m = r.ReadLine();
}
Console.WriteLine("{0}\n", m);
r.Close();
Run Code Online (Sandbox Code Playgroud)