11

我有一个 60GB 的 csv 文件,我需要对其进行一些修改。客户希望对文件数据进行一些更改,但我不想重新生成该文件中的数据,因为这需要 4 天时间。

如何逐行读取文件(而不是将其全部加载到内存中!),并在进行时对这些行进行编辑,替换某些值等?

4

3 回答 3

15

该过程将是这样的:

  1. 打开一个StreamWriter临时文件。
  2. 打开一个StreamReader到目标文件。
  3. 对于每一行:
    1. 根据分隔符将文本拆分为列。
    2. 检查要替换的值的列,然后替换它们。
    3. 使用分隔符将列值重新连接在一起。
    4. 将该行写入临时文件。
  4. 完成后,删除目标文件,并将临时文件移动到目标文件路径。

关于第 2 步和第 3.1 步的注意事项:如果您对文件的结构有信心并且它足够简单,那么您可以按照所述开箱即用地完成所有这些操作(稍后我将包含一个示例)。但是,可能需要注意 CSV 文件中的一些因素(例如识别何时在列值中按字面意思使用分隔符)。您可以自己苦苦挣扎,或尝试现有的解决方案


StreamReader仅使用and 的基本示例StreamWriter

var sourcePath = @"C:\data.csv";
var delimiter = ",";
var firstLineContainsHeaders = true;
var tempPath = Path.GetTempFileName();
var lineNumber = 0;

var splitExpression = new Regex(@"(" + delimiter + @")(?=(?:[^""]|""[^""]*"")*$)");

using (var writer = new StreamWriter(tempPath))
using (var reader = new StreamReader(sourcePath))
{
    string line = null;
    string[] headers = null;
    if (firstLineContainsHeaders)
    {
        line = reader.ReadLine();
        lineNumber++;

        if (string.IsNullOrEmpty(line)) return; // file is empty;

        headers = splitExpression.Split(line).Where(s => s != delimiter).ToArray();

        writer.WriteLine(line); // write the original header to the temp file.
    }

    while ((line = reader.ReadLine()) != null)
    {
        lineNumber++;

        var columns = splitExpression.Split(line).Where(s => s != delimiter).ToArray();

        // if there are no headers, do a simple sanity check to make sure you always have the same number of columns in a line
        if (headers == null) headers = new string[columns.Length];

        if (columns.Length != headers.Length) throw new InvalidOperationException(string.Format("Line {0} is missing one or more columns.", lineNumber));

        // TODO: search and replace in columns
        // example: replace 'v' in the first column with '\/': if (columns[0].Contains("v")) columns[0] = columns[0].Replace("v", @"\/");

        writer.WriteLine(string.Join(delimiter, columns));
    }

}

File.Delete(sourcePath);
File.Move(tempPath, sourcePath);
于 2012-12-21T07:15:15.260 回答
6

内存映射文件是 .NET Framework 4 中的一项新功能,可用于编辑大文件。在这里阅读http://msdn.microsoft.com/en-us/library/dd997372.aspx 或谷歌内存映射文件

于 2012-12-21T07:18:22.167 回答
1

只需使用 streamreader 逐行读取文件,然后使用 REGEX!世界上最神奇的工具。

using (var sr = new StreamReader(new FileStream(@"C:\temp\file.csv", FileMode.Open)))
        {
            var line = sr.ReadLine();
            while (!sr.EndOfStream)
            {
                // do stuff

                line = sr.ReadLine();
            }

        }
于 2012-12-21T07:23:28.380 回答