阅读文本文件的最后一行

时间:2012-07-24 06:52:34

标签: c#

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

  1. 查找文件的最后一行。
  2. 处理最后一行文件。
  3. 我希望这是有道理的。

6 个答案:

答案 0 :(得分:60)

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

除非您的文件如此大,否则您真的无法全部阅读,我只会使用:

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

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

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

答案 1 :(得分:9)

我只想合并File.ReadLines(path)Enumerable.Last

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

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

答案 2 :(得分:9)

第一部分:

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

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

首选ReadLines。

答案 3 :(得分:6)

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

答案 4 :(得分:3)

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

此问题的主要用例之一是抓取日志文件的末尾。不幸的是,当日志文件进入兆字节时,其他答案会死得很可怕。想象一下,在一个微小的单核VPS上,每次通话都会运行每一行......哎呀。

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

您可以使用“How to read a text file reversely with iterator in C#”的解决方案,但要注意代码相当复杂。如果您只需要一个简单的UTF-8线路预告片,这个解决方案将非常好用,即使在大型日志文件上也能表现出色。

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

当您的SSH端口面向公共端口时,您会惊讶于auth.log的大小。是的,VPN,我知道......:)

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 UTF8FileLastLineReader
{
    /// <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 ReadLastLineFromUTF8EncodedFile(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);
        }
    }
}

答案 5 :(得分:-1)

import Control.Monad (liftM2)
liftM2 (==) [x,y] [2,3]
[False,False,False,True]