C# 读取文本文件的最后一行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11625595/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 18:33:19  来源:igfitidea点击:

Read last line of text file

c#

提问by Debbie Dippenaar

I need to know how to read the last line of a text file. I need to find the line and then process it into a SQL database... I've been reading around and scouring the web but am battling to find the proper way to do this. I.e.:

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

  1. Find last line of file.
  2. Process last line of file.
  1. 找到文件的最后一行。
  2. 处理文件的最后一行。

I hope this makes sense.

我希望这是有道理的。

回答by Jon Skeet

There are two ways: simple and inefficient, or horrendously complicated but efficient. The complicated version assumes a sane encoding.

有两种方法:简单而低效,或极其复杂但有效。复杂的版本假设一个健全的编码。

Unless your file is sobig that you really can't afford to read it all, I'd just use:

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

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

Note that this uses File.ReadLines, notFile.ReadAllLines. If you're using .NET 3.5 or earlier you'd need to use File.ReadAllLinesor write your own code - ReadAllLineswill read the wholefile into memory in one go, whereas ReadLinesstreams it.

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

Otherwise, the complicated way is to use code similar to this. It tries to read backwards from the end of the file, handling nastiness such as UTF-8 multi-byte characters. It's not pleasant.

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

回答by Tim Schmelter

I would simply combine File.ReadLines(path)and Enumerable.Last:

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

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

It streams the lines and does not load all into memory as File.ReadAllLines.

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

回答by juFo

First part:

第一部分:

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

or

或者

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

ReadLines is prefered.

ReadLines 是首选。

回答by krish

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

回答by luuk

string last = File.ReadLines(@"C:\file.txt").Last();
string lastsymbol = last[last.Count - 1];

回答by jjxtra

Note: All this code assumes UTF-8. If you need to support a code page that uses double wide chars like Unicode, then you need to add extra checks to the char before and/or after the newline to make sure it is really a newline.

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

One of the primary use cases of this question is scraping the end of a log file. The other answers unfortunately die a horrible death when log files get into the megabytes. Imagine running every line on every call on a tiny single core VPS... yikes.

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

The nice thing about UTF-8 is that when you hit a '\n' character, you don't have to worry about any dependent bytes because any byte with the high bit clear in UTF8-8 is simply an ASCII character. Pretty handy!

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

You could use the solution at 'How to read a text file reversely with iterator in C#', but be aware that the code is fairly complex. If you just need a simple UTF-8 line trailer, this solution will work very well and perform great even on large log files.

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

If you are monitoring lots of files at once and are using something like a FileSystemWatcher in C#, this performance gain will be very important. I am using very similar code on a cheap single cpu Linux VPS to monitor login failures and put ip addresses in the firewall in my MIT licensed project https://github.com/DigitalRuby/IPBan, using https://github.com/DigitalRuby/IPBan/blob/master/Core/IPBanLogFileScanner.cs(which handles multiple new lines at once).

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

You'd be suprised at how large auth.log can get when your SSH port is public facing. Yes, a VPN, I know... :)

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

C# Code ...

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