【问题标题】:Processing large text file in C#在 C# 中处理大型文本文件
【发布时间】:2011-06-24 07:18:00
【问题描述】:

我有 4GB 以上的文本文件(csv 格式),我想在 c# 中使用 linq 处理这个文件。

我在加载 csv 并转换为类后运行复杂的 linq 查询?

但文件大小为 4gb,尽管应用程序内存是文件大小的两倍。

如何处理(linq 和新结果)大文件?

谢谢

【问题讨论】:

  • 你使用的是什么版本的 .NET

标签: c# .net string c#-4.0 .net-4.0


【解决方案1】:

您可以逐行读取和处理文件,而不是将整个文件加载到内存中。

using (var streamReader = new StreamReader(fileName))
{
    string line;
    while ((line = streamReader.ReadLine()) != null)
    {
        // analize line here
        // throw it away if it does not match
    }
}

[编辑]

如果您需要对文件中的数据运行复杂的查询,正确的做法是将数据加载到数据库并让 DBMS 负责数据检索和内存管理。

【讨论】:

  • 如果所有文本都在一行中没有回车怎么办?
  • @Cody - 我假设 csv 文件不是单行文件。
  • 然后你会将整行处理为字节流,而不是行流。
  • @cody 那么它要么是一条可能必须立即处理的记录,因为您无法预先知道 lin 查询中将包含哪些字段,或者使用了不寻常的记录分隔符并且 OP 很可能已经包含了它,因为它是一个关键的细节
  • 我应该将所有数据加载到内存中以运行 linq 查询并创建新结果?
【解决方案2】:

我认为这是一个好方法... CSV

【讨论】:

  • link 问题是这个读取字节 500MB 但内存 2GB
【解决方案3】:

如果您使用的是 .NET 4.0,则可以使用 Clay,然后编写一个方法,该方法返回一个 IEnumerable 行,这使得下面的代码成为可能

from record in GetRecords("myFile.csv",new []{"Foo","Bar"},new[]{","})
where record.Foo == "Baz"
select new {MyRealBar = int.Parse(record.Bar)

将 CSV 投影到一系列 Clay 对象中的方法可以创建如下:

 private IEnumerable<dynamic> GetRecords(
                    string filePath,
                    IEnumerable<string> columnNames, 
                    string[] delimiter){
            if (!File.Exists(filePath))
                yield break;
            var columns = columnNames.ToArray();
            dynamic New = new ClayFactory();
            using (var streamReader = new StreamReader(filePath)){
                var columnLength = columns.Length;
                string line;
                while ((line = streamReader.ReadLine()) != null){
                    var record = New.Record();
                    var fields = line.Split(delimiter, StringSplitOptions.None);
                    if(fields.Length != columnLength)
                        throw new InvalidOperationException(
                                 "fields count does not match column count");
                    for(int i = 0;i<columnLength;i++){
                        record[columns[i]] = fields[i];
                    }
                    yield return record;
                }
            }
        }

【讨论】:

  • 感谢您的建议,我尝试了此解决方案,但速度很慢,并且存在相同的内存问题。
  • @oguzh4n 哦,我故意没有考虑速度,因为您在帖子中没有提到这一点。在任何一天,我都更喜欢可读性(在这种情况下是呼叫站点)而不是速度。关于内存问题。如果您可以更准确地了解它们,它们可以被修复。这不必一次保存超过一行的文本文件和一个粘土对象(和一点),所以上面的草稿有什么内存问题都可以修复
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-02
  • 2012-05-10
  • 1970-01-01
  • 2011-05-16
相关资源
最近更新 更多