2010-07-30 75 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

相关问题