2010-07-30 108 views
2

我想弄清楚如何分割每個文件中的行數。這些文件是csv,我不能按字節來完成。我需要通過線路來完成。 20k似乎是每個文件的好數字。在特定位置閱讀流的最佳方式是什麼? Stream.BaseStream.Position?所以如果我讀了第一條20k線,我會開始在39,999的位置?我怎麼知道我幾乎在文件的末尾?感謝所有通過C#中的行數將大文件分割成更小的文件?

+1

您是否嘗試過20K調用READLINE? – strager 2010-07-30 17:41:35

+2

你根本不需要去尋求。你應該逐行閱讀它,一旦你打到20k就切換到一個新的文件。 – Fosco 2010-07-30 17:42:29

+0

是的,我寫完這些後就去剪髮了。它讓我明白,我可以閱讀它最後並做一個readline。謝謝! – DDiVita 2010-07-30 18:55:05

回答

3
using (System.IO.StreamReader sr = new System.IO.StreamReader("path")) 
{ 
    int fileNumber = 0; 

    while (!sr.EndOfStream) 
    { 
     int count = 0; 

     using (System.IO.StreamWriter sw = new System.IO.StreamWriter("other path" + ++fileNumber)) 
     { 
      sw.AutoFlush = true; 

      while (!sr.EndOfStream && ++count < 20000) 
      { 
       sw.WriteLine(sr.ReadLine()); 
      } 
     } 
    } 
} 
+0

這看起來對我來說是最直接的,儘管爲了內存的緣故,我可能會用每次寫入來刷新寫入緩衝區。如果每行都是100字節,就會產生1000行100k和20000 2Mb,這不是一噸內存,而是一個不必要的腳印。 – 2010-07-30 18:06:14

+0

@Jimmy - 我添加了'AutoFlush = True',每次寫入後自動刷新。 – 2010-07-30 18:16:10

+0

AutoFlush在StreamWriter上是個不錯的主意,因爲它會在每個單個字符(我看過代碼)後刷新。如果您在創建StreamWriter時未指定緩衝區大小,則默認只有128個字符,但仍然比沒有緩衝區更好。 – Tergiver 2010-07-30 19:37:03

3

我會做這樣的:

// helper method to break up into blocks lazily 

public static IEnumerable<ICollection<T>> SplitEnumerable<T> 
    (IEnumerable<T> Sequence, int NbrPerBlock) 
{ 
    List<T> Group = new List<T>(NbrPerBlock); 

    foreach (T value in Sequence) 
    { 
     Group.Add(value); 

     if (Group.Count == NbrPerBlock) 
     { 
      yield return Group; 
      Group = new List<T>(NbrPerBlock); 
     } 
    } 

    if (Group.Any()) yield return Group; // flush out any remaining 
} 

// now it's trivial; if you want to make smaller files, just foreach 
// over this and write out the lines in each block to a new file 

public static IEnumerable<ICollection<string>> SplitFile(string filePath) 
{ 
    return File.ReadLines(filePath).SplitEnumerable(20000); 
} 

那是不是你是否足夠?你提到了從一個位置移動到另一個位置,但我不明白爲什麼這是必要的。

+1

這也適用!天哪。我喜歡這個地方! – DDiVita 2010-07-30 18:55:44

4
int index=0; 
var groups = from line in File.ReadLines("myfile.csv") 
      group line by index++/20000 into g 
      select g.AsEnumerable(); 
int file=0; 
foreach (var group in groups) 
     File.WriteAllLines((file++).ToString(), group.ToArray()); 
+0

您需要使用'File.ReadLines'而不是'ReadAllLines' - 'ReadAllLines'一次將它全部讀入內存。另外,在分組函數中使用'index'就像這樣會讓我大吃一驚。 – mquander 2010-07-30 17:48:52

+0

更改爲ReadLines,謝謝 – 2010-07-30 17:51:02

+0

+1這是一個非常有趣的使用linq – BlackICE 2010-07-30 17:54:13

相關問題