如何在.NET中读取大型(1 GB)txt文件?

时间:2010-11-25 04:21:59

标签: c#

我有一个1 GB的文本文件,我需要逐行阅读。最好和最快的方法是什么?

private void ReadTxtFile()
{            
    string filePath = string.Empty;
    filePath = openFileDialog1.FileName;
    if (string.IsNullOrEmpty(filePath))
    {
        using (StreamReader sr = new StreamReader(filePath))
        {
            String line;
            while ((line = sr.ReadLine()) != null)
            {
                FormatData(line);                        
            }
        }
    }
}

FormatData()中,我检查必须与单词匹配的行的起始单词,并根据该增量一个整数变量。

void FormatData(string line)
{
    if (line.StartWith(word))
    {
        globalIntVariable++;
    }
}

9 个答案:

答案 0 :(得分:47)

如果您使用的是.NET 4.0,请尝试MemoryMappedFile,这是此方案的设计类。

您可以使用StreamReader.ReadLine

答案 1 :(得分:31)

使用StreamReader可能是一种方法,因为您不希望一次将整个文件放在内存中。 MemoryMappedFile比随机读取更适合随机访问(顺序读取速度快10倍,内存映射速度是随机访问速度的十倍)。

您也可以尝试从FileOptions设置为SequentialScan的文件流中创建您的streamreader(请参阅 FileOptions Enumeration ),但我怀疑它会产生多大的影响。

然而,有一些方法可以使您的示例更有效,因为您在与阅读相同的循环中进行格式化。你正在浪费时钟周期,所以如果你想要更高的性能,那么使用多线程异步解决方案会更好,其中一个线程读取数据而另一个线程在可用时对其进行格式化。 Checkout BlockingColletion可能符合您的需求:

Blocking Collection and the Producer-Consumer Problem

如果你想要尽可能快的性能,根据我的经验,唯一的方法是顺序读入一大块二进制数据并将其反序列化为文本并行,但代码开始变得复杂。

答案 2 :(得分:15)

您可以使用LINQ

int result = File.ReadLines(filePath).Count(line => line.StartsWith(word));

File.ReadLines返回IEnumerable<String>,懒惰地从文件中读取每一行而不将整个文件加载到内存中。

Enumerable.Count计算以单词开头的行。

如果您是从UI线程调用此方法,请使用BackgroundWorker

答案 3 :(得分:10)

Probably to read it line by line.

你不应试图通过阅读结束然后处理来强制它进入记忆。

答案 4 :(得分:8)

StreamReader.ReadLine应该可以正常工作。让框架选择缓冲,除非你通过剖析知道你可以做得更好。

答案 5 :(得分:6)

答案 6 :(得分:1)

我在Agenty的生产服务器中遇到同样的问题,我们看到大文件(有时10-25 gb(\ t)制表符分隔的txt文件)。经过大量的测试和研究后,我找到了使用for / foreach循环读取大块文件的最佳方法,并使用File.ReadLines()设置偏移和限制逻辑。

int TotalRows = File.ReadLines(Path).Count(); // Count the number of rows in file with lazy load
int Limit = 100000; // 100000 rows per batch
for (int Offset = 0; Offset < TotalRows; Offset += Limit)
{
  var table = Path.FileToTable(heading: true, delimiter: '\t', offset : Offset, limit: Limit);

 // Do all your processing here and with limit and offset and save to drive in append mode
 // The append mode will write the output in same file for each processed batch.

  table.TableToFile(@"C:\output.txt");
}

请参阅我的Github库中的完整代码:https://github.com/Agenty/FileReader/

完全披露 - 我为拥有此图书馆和网站的公司Agenty工作

答案 7 :(得分:1)

我的文件超过13 GB:

enter image description here

您可以使用我的课程:

public static void Read(int length)
    {
        StringBuilder resultAsString = new StringBuilder();

        using (MemoryMappedFile memoryMappedFile = MemoryMappedFile.CreateFromFile(@"D:\_Profession\Projects\Parto\HotelDataManagement\_Document\Expedia_Rapid.jsonl\Expedia_Rapi.json"))
        using (MemoryMappedViewStream memoryMappedViewStream = memoryMappedFile.CreateViewStream(0, length))
        {
            for (int i = 0; i < length; i++)
            {
                //Reads a byte from a stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream.
                int result = memoryMappedViewStream.ReadByte();

                if (result == -1)
                {
                    break;
                }

                char letter = (char)result;

                resultAsString.Append(letter);
            }
        }
    }

此代码将从文件的开始读取文本,直到您将其传递给方法 Read(int length)的长度,然后填充resultAsString变量。

它将返回以下文字:

答案 8 :(得分:0)

我一次读取10,000字节的文件。然后我将分析这10,000个字节并将它们分成行并将它们提供给FormatData函数。

在多个线程上拆分读数和线分析的加分点。

我肯定会使用StringBuilder来收集所有字符串,并且可能会构建一个字符串缓冲区,以便始终在内存中保留大约100个字符串。