2014-10-28 54 views
0

我有一个非常大的CSV文件,大约有1,000,000行,它需要大约500 MB的内存。我不必读取所有文件。我想从文件中读取每一百行。我尝试按ReadLines来做,但它确实很慢,更快的是ReadAllLines阅读从CSV中选择的行

我的代码:

for (int i = 0; i < 10000; i++) 
{ 
    tableOfString[i]=File.ReadLines("TestCSV.csv").Skip(i*100).Take(1).First(); 
    //or 
    tableOfString[i] = File.ReadLines("TestCSV.csv").ElementAtOrDefault(i*100); 
} 

我读到一些读者:

有anyb ody得到了解决方案?我只想从CSV中读取某些行,而不是整个文件。

+0

商店都在一个字符串[],而不是使用' File.ReadLines'。你可以使用'File.ReadAllLines'。 '文件。ReadLines'返回一个IQueryable,所以当你访问它时,你会查询所有行。 – 2014-10-28 09:28:37

+1

你是说你不想把整个文件读入内存? – DavidG 2014-10-28 09:29:36

+0

'File.ReadLines(“TestCSV.csv”)。ElementAtOrDefault(i * 100);' – artm 2014-10-28 09:35:00

回答

2

ReadLines不慢。问题在于,您在每次迭代中重新读取文件至所需行。 (当i = 1时,读取行0-100 ...当i = 2时,读取行0-200等)

您应该避免多次呼叫File.ReadLines。换句话说,只需打开一次文件并使用Where筛选掉不想使用的行。因此,尝试这个:

var filteredLines = File.ReadLines("TestCSV.csv") 
    .Select((Text, Index) => new {Text, Index}) 
    .Where(x => x.Index % 100 == 0); 

foreach(var line in filteredLines) 
{ 
    tableOfString[line.Index] = line.Text; 
} 

不知道你如何您创建或使用tableOfString,但如果它仅用于获取这些行,那么你可以你的LINQ查询直接转换成数组(你不不用为了填充阵列中的for循环):

var tableOfString = File.ReadLines("TestCSV.csv") 
    .Where((x, i) => i % 100 == 0) 
    .ToArray(); 
+0

这是一个很好的解决方案,但它仍然遍历文件中的所有行,并且每隔百分之一就会节省RAM。 :) 是否有可能无法遍历所有内容并只采用这些选定的行?它会更快。 现在我在文件中有500,000行,我只用了1000行,但它仍然需要2秒才能读取。 – user3447900 2014-10-28 10:41:36

0

起初,如果您不想将完整的文件加载到内存中,那么File.ReadLines和File.ReadAllLines不起作用。

如果您只想将文件的几个字节读入RAM,我会建议您使用File.OpenRead,并将所需的部分读入缓冲区。像How can I read/stream a file without loading the entire file into memory?

但是,比你有问题,你不能跳过99行,只能读100行。如果要实现此目的,则需要知道每行的大小以设置读取方法中的偏移量。

最简单的版本是与File.ReadAllLine一起使用,并且迭代字符串数组或使用Linq。

1

Accordding到你的代码中想要得到的CSV文件的

0th, 100th, 200th ... 1000000th线,并将它们存储在tableOfString[]

你可以那样做:

tableOfString = File 
    .ReadLines("TestCSV.csv") 
    .Where((line, index) => (index % 100) == 0) 
    .ToArray(); 

重新打开文件时,你做的(这是慢)在一个循环是指一个伟大的开销