如何在不循环ReadLine()的情况下读取文本文件的特定行号

本文关键字:文件 取文本 读取 情况下 循环 ReadLine | 更新日期: 2023-09-27 18:13:06

是否有一个类可以让你在c#中逐行读取行号?

我知道关于StreamReader和TextFieldParser,但AFAIK那些没有这个功能。例如,如果我知道文本文件中的行号34572包含某些数据,那么不必多次调用StreamReader.ReadLine() 34572就好了。

如何在不循环ReadLine()的情况下读取文本文件的特定行号

除非文件具有精确且预先确定的格式,例如每行具有相同的长度,否则无法在文本文件中查找。

为了找到第i行,必须找到第i-1行结尾。如果您不知道这些行结束的位置,那么您必须读取整个文件,直到第i行。

这不是c#的问题——这是行终止符的问题。没有办法跳到34572行,因为你不知道它是什么时候开始的——你唯一知道的是它是从你找到34571 'r'n s之后开始的。如果您需要这个功能,您根本不想使用文本文件:)

一个简单(但仍然很慢)的方法是使用File.ReadLines(...):

var line = File.ReadLines(fileName).Skip(34571).FirstOrDefault();
然而,最好的方法是知道该行的实际字节偏移量。如果您记住了偏移量而不是行号,则可以简单地在流中查找,避免读取不必要的数据。然后像往常一样继续读这一行:
streamReader.BaseStream.Seek(offset, SeekOrigin.Begin);
var line = streamReader.ReadLine();

如果文件只是附加的(例如日志文件),并且你可以记住书签,这是很有用的。只有当文件没有在书签前面修改时才会起作用。

总的来说,有三个选项:

  • 添加索引——创建一个包含所有(或部分)行起始偏移量的表
  • 有一个固定的行长度-这允许你在没有索引的情况下进行可预测的搜索;然而,这将不能很好地工作与unicode,所以这是相当无用的这些天
  • 解析文件-这几乎相当于逐行读取文件,唯一的优化是,你实际上不需要分配字符串-一个简单的可重用的byte缓冲区将做。

当性能很重要时,文本格式不被首选是有原因的——当您使用用户可编辑的一般文本格式时,第三种选择是唯一的选择。因此,从JSON, XML,文本日志文件等中读取总是意味着至少读取到您想要的行。

这可能不是您的情况,但是如果您知道每行的长度,您可以计算您要查找的行的开始索引字节,并可以像下面这样:

FileStream fs = new FileStream("fullFileName");
fs.Seek(startByte, SeekOrigin.Current)
for (long offset = startByte; offset < fs.Length; offset++)
{
     fs.Seek(-1, SeekOrigin.Current);
     char value = (char)((byte)fs.ReadByte());
    .
    .
    .
//To determine the end of each line you can use the conditions below
     if (value == 0xA)//  hex 'n
     {
          if (offset == fs.Length)
              continue;
     }
     else if (value == 0xD)// hex 'r
     {
         if (offset == fs.Length - 1)
              continue;
     }
}