如何在不循环ReadLine()的情况下读取文本文件的特定行号
本文关键字:文件 取文本 读取 情况下 循环 ReadLine | 更新日期: 2023-09-27 18:13:06
是否有一个类可以让你在c#中逐行读取行号?
我知道关于StreamReader和TextFieldParser,但AFAIK那些没有这个功能。例如,如果我知道文本文件中的行号34572包含某些数据,那么不必多次调用StreamReader.ReadLine()
34572就好了。
除非文件具有精确且预先确定的格式,例如每行具有相同的长度,否则无法在文本文件中查找。
为了找到第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;
}
}