我想逐行读取文本文件。我想知道我是否在。net c#范围内尽可能高效地完成它。

这是我目前正在尝试的:

var filestream = new System.IO.FileStream(textFilePath,
                                          System.IO.FileMode.Open,
                                          System.IO.FileAccess.Read,
                                          System.IO.FileShare.ReadWrite);
var file = new System.IO.StreamReader(filestream, System.Text.Encoding.UTF8, true, 128);

while ((lineOfText = file.ReadLine()) != null)
{
    //Do something with the lineOfText
}

当前回答

如果文件大小不大,那么读取整个文件并随后拆分它会更快

var filestreams = sr.ReadToEnd().Split(Environment.NewLine, 
                              StringSplitOptions.RemoveEmptyEntries);

其他回答

虽然file . readalllines()是读取文件的最简单方法之一,但它也是最慢的方法之一。

如果你只是想读取文件中的行而不做太多事情,根据这些基准测试,读取文件的最快方法是古老的方法:

using (StreamReader sr = File.OpenText(fileName))
{
        string s = String.Empty;
        while ((s = sr.ReadLine()) != null)
        {
               //do minimal amount of work here
        }
}

然而,如果你必须对每一行做很多事情,那么本文得出的结论是,最好的方法是以下(如果你知道你要读取多少行,那么预先分配一个字符串[]会更快):

AllLines = new string[MAX]; //only allocate memory here

using (StreamReader sr = File.OpenText(fileName))
{
        int x = 0;
        while (!sr.EndOfStream)
        {
               AllLines[x] = sr.ReadLine();
               x += 1;
        }
} //Finished. Close the file

//Now parallel process each line in the file
Parallel.For(0, AllLines.Length, x =>
{
    DoYourStuff(AllLines[x]); //do your work here
});

如果文件大小不大,那么读取整个文件并随后拆分它会更快

var filestreams = sr.ReadToEnd().Split(Environment.NewLine, 
                              StringSplitOptions.RemoveEmptyEntries);

如果您有足够的内存,我发现通过将整个文件读入内存流,然后打开流阅读器来读取行,可以获得一些性能提升。只要您实际上打算读取整个文件,这就可以产生一些改进。

为了找到逐行读取文件的最快方法,您必须进行一些基准测试。我在我的电脑上做了一些小的测试,但你不能指望我的结果适用于你的环境。

使用StreamReader。ReadLine

这基本上就是你的方法。由于某种原因,您将缓冲区大小设置为最小值(128)。增加这个值通常会提高性能。默认大小是1024,其他好的选择是512 (Windows中的扇区大小)或4096 (NTFS中的集群大小)。您必须运行基准测试来确定最佳缓冲区大小。更大的缓冲区——如果不是更快的话——至少不会比更小的缓冲区慢。

const Int32 BufferSize = 128;
using (var fileStream = File.OpenRead(fileName))
  using (var streamReader = new StreamReader(fileStream, Encoding.UTF8, true, BufferSize)) {
    String line;
    while ((line = streamReader.ReadLine()) != null)
    {
      // Process line
    }
  }

FileStream构造函数允许您指定FileOptions。例如,如果从头到尾顺序读取一个大文件,则可以使用FileOptions.SequentialScan。同样,基准测试是您所能做的最好的事情。

使用文件。readline

这与您自己的解决方案非常相似,不同之处是它使用固定缓冲区大小为1024的StreamReader实现。在我的计算机上,与缓冲区大小为128的代码相比,这将导致稍微更好的性能。但是,您可以通过使用更大的缓冲区大小来获得相同的性能提升。此方法使用迭代器块实现,并且不会为所有行消耗内存。

var lines = File.ReadLines(fileName);
foreach (var line in lines)
  // Process line

使用文件。ReadAllLines

这与前面的方法非常相似,只是该方法增加了用于创建返回的行数组的字符串列表,因此内存需求更高。但是,它返回String[],而不是IEnumerable<String>,允许您随机访问这些行。

var lines = File.ReadAllLines(fileName);
for (var i = 0; i < lines.Length; i += 1) {
  var line = lines[i];
  // Process line
}

使用字符串。分裂

这种方法相当慢,至少在大文件(在511 KB文件上测试)上是如此,可能是由于String。实现Split。它还为所有行分配一个数组,与您的解决方案相比,增加了所需的内存。

using (var streamReader = File.OpenText(fileName)) {
  var lines = streamReader.ReadToEnd().Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
  foreach (var line in lines)
    // Process line
}

我的建议是使用File。因为它干净高效。如果需要特殊的共享选项(例如使用FileShare.ReadWrite),可以使用自己的代码,但应该增加缓冲区大小。

如果你正在使用。net 4,只需使用File即可。ReadLines为你做了所有这些。我怀疑它和你的差不多,除了它也可以使用FileOptions。SequentialScan和一个更大的缓冲区(128看起来很小)。