2012-12-21 13 views
11

我有一個60GB的csv文件,我需要做一些修改。客戶希望對文件數據進行一些更改,但我不想重新生成該文件中的數據,因爲需要4天才能完成。如何一次讀取一行csv文件,並隨時替換/編輯某些行?

如何逐行讀取文件(並非全部加載到內存中!),並對這些行進行編輯,替換某些值等。

+1

你爲什麼不嘗試使用Hadoop地圖降低.... –

+0

您將能夠做的只有修改線將有長度不超過原線路長度 –

+0

修改爲什麼不只是寫一個新文件?所以:1.閱讀2.修改3.寫入複製。那是你不想做的事情,還是你正在尋找一種「優雅」的方式來做到這一點? – StampedeXV

回答

13

的過程會是這樣的:

  1. 打開StreamWriter到一個臨時文件。
  2. 打開目標文件的StreamReader
  3. 對於每行:
    1. 根據分隔符將文本拆分爲列。
    2. 檢查要替換的值的列,並將其替換。
    3. 使用分隔符將列值加回到一起。
    4. 將行寫入臨時文件。
  4. 完成後,刪除目標文件,並將臨時文件移動到目標文件路徑。

有關步驟2和3.1的注意事項:如果您對文件的結構很有信心,並且它足夠簡單,那麼您可以按照描述的方式完成所有這些操作(我將在一會兒包括一個示例)。但是,CSV文件中可能需要注意的因素(例如識別分隔符何時在字段值中逐字地使用)。你可以自己完成這個嘗試,或者試試existing solution。只是用StreamReaderStreamWriter


基本例如:

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); 
+0

這絕對是簡單和最直接的方式去。 – richard

+0

我更新它來處理分隔符的字面出現。 – HackedByChinese

+0

有一件事,我沒有想到大小。最終的'File.Move'可能會很慢。相反,您可能只是在源文件所在的文件夾中創建臨時文件,然後刪除源文件並重命名temp(而不是使用'GetTempFileName'和'File.Move')。 – HackedByChinese

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(); 
      } 

     } 
在這種情況下
相關問題