36

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

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

6 回答 6

83

有两种方法:简单而低效,或者极其复杂但高效。复杂的版本假定一个理智的编码。

除非您的文件太大以至于您真的无法阅读全部内容,否则我只会使用:

var lastLine = File.ReadLines("file.txt").Last();

请注意,这使用File.ReadLines而不是 File.ReadAllLines。如果您使用的是 .NET 3.5 或更早版本,则需要使用File.ReadAllLines或编写自己的代码 -一次性ReadAllLines整个文件读入内存,同时ReadLines将其流式传输。

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

于 2012-07-24T06:57:38.937 回答
9

第一部分:

File.ReadAllLines(@"c:\some\path\file.txt").Last();

或者

File.ReadLines(@"c:\some\path\file.txt").Last();

ReadLines 是首选。

于 2012-07-24T07:00:24.447 回答
9

我会简单地结合File.ReadLines(path)Enumerable.Last

String last = File.ReadLines(@"C:\file.txt").Last();

它流式传输行并且不会将所有行加载到内存中File.ReadAllLines

于 2012-07-24T07:00:10.700 回答
6
string m = "";
StreamReader r = new StreamReader("file_path");
while (r.EndOfStream == false)
{
    m = r.ReadLine();
}
Console.WriteLine("{0}\n", m);
r.Close();
于 2013-10-15T04:25:17.187 回答
4

注意:所有这些代码都假定为 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);
        }
    }
}
于 2018-06-12T14:37:33.707 回答
-2
string last = File.ReadLines(@"C:\file.txt").Last();
string lastsymbol = last[last.Count - 1];
于 2016-11-05T17:38:31.880 回答