2012-06-14 128 views
1

我有一个巨大的文件(1.2GB)的特征向量保存为csv文件。 为了通过这些界限,我创建了一个python类,它可以一次一个批次地从巨型文件中将行加载到内存中。python,寻找,告诉,阅读。从巨型csv文件读取行

为了让这个类知道在文件中准确读取批量batch_size的完整行(可以说batch_size = 10,000),在第一次使用巨型文件时,这个类会遍历整个文件一次,并注册每行的偏移量,并将这些偏移量保存到帮助文件中,以便稍后它可以“file.seek(starting_offset); batch = file.read(num_bytes)”读取下一批行。

首先,我实现了线偏移的报名以这种方式:

offset = 0; 
    line_offsets = []; 
    for line in self.fid: 
     line_offsets.append(offset); 
     offset += len(line); 

和它的工作与可爱giant_file1。

但随后我在这个类的帮助下处理了这些特性并创建了giant_file2(具有标准化的特性)。 接下来,当我想读取批量的行格式giant_file2时,它失败了,因为它将读取的批处理字符串不在正确的位置(例如,读取类似“-00 \ n15.467e-04”,.. 。“而不是”15.467e-04,... \ n“)。

因此,我试图改变线偏移计算部分:

offset = 0; 
    line_offsets = []; 
    while True: 
     line = self.fid.readline(); 

     if (len(line) <= 0): 
      break; 

     line_offsets.append(offset); 
     offset = self.fid.tell(); 

代替线的累积长度,主要的变化是,偏移寄存器我从fid.tell的结果取()。

该版本与giant_file2配合良好,但与giant_file1失败。

我进一步调查了它,发现函数seek(),tell()和read()彼此不一致。 例如:

fid = file('giant_file1.csv'); 
fid.readline(); 
>>>'0.089,169.039,10.375,-30.838,59.171,-50.867,13.968,1.599,-26.718,0.507,-8.967,-8.736,\n' 
fid.tell(); 
>>>67L 
fid.readline(); 
>>>'15.375,91.43,15.754,-147.691,54.234,54.478,-0.435,32.364,4.64,29.479,4.835,-16.697,\n' 
fid.seek(67); 
fid.tell(); 
>>>67L 
fid.readline(); 
>>>'507,-8.967,-8.736,\n' 

有一些矛盾在这里:当我(按fid.tell())在67字节定位一次读取的行是一回事,并在第二次(FID再次当.tell()报告我位于字节67)读取的行是不同的。

我不能相信tell()和seek()将我放到想要的位置,从所需行的开头读取。 在另一方面,当我使用(与giant_file1)字符串的长度作为参考的寻求()我得到正确的位置:

fid.seek(0); 
line = fid.readline(); 
fid.tell(); 
>>>87L 
len(line); 
>>>86 
fid.seek(86); 
fid.readline(); 
>>>'15.375,91.43,15.754,-147.691,54.234,54.478,-0.435,32.364,4.64,29.479,4.835,-16.697,\n' 

这是怎么回事呢?

我能想到的giant_file1和giant_file2之间的唯一区别是,在giant_file1中,值是用小数点(例如-0.435)写的,在giant_file2中它们都是科学格式(例如-4.350e-01) 。我不认为他们中的任何一个都是用unicode编码的(我认为是这样,因为我用简单的file.read()读取的字符串似乎可读,我怎么确定?)。

我非常感谢您的帮助,解释,理由和可能的解决方案(或解决方法)。

谢谢, Yonatan。

+3

是否有理由不能在处理文件时迭代文件行 –

+3

除此之外,为什么不使用[csv'模块](http://docs.python.org/library/csv .html),它允许你逐行处理? –

+0

我同意@Jakob Bowyer,在计算偏移量时,你反复遍历整个文件中的所有行。那么,为什么不处理呢? – Dhara

回答

2

我认为你有一个换行符问题。检查giant_file1.csv是否以\ n或\ r \ n结尾行如果以文本模式打开该文件,该文件将返回仅以\ n结尾的行,并丢弃多余的\ r。所以,当你查看返回的行的长度时,它将是实际文件位置的1(它不仅消耗了\ n,而且还消耗了\ r \ n)。当然,当你阅读更多的行时,这些错误会累积下来。

解决的办法是以二进制模式打开文件。在这种模式下,没有\ r \ n - > \ n减少,所以您的行长度符合您的文件tell()查询。

我希望能为你解决它 - 因为这是一个简单的解决方案。 :)祝你的项目和快乐的编码!

+0

听起来很可能是问题所在。 – martineau

+0

就是这样。谢谢。 – user1456524

+0

谢谢你们的建议。实际上,我只尝试了第一种解决方案 - 我使用模式“rb”(读,二进制)而不是“r”打开文件,并解决了问题:1)现在读取的字符串长度与告诉()。 2)在giant_file2(在Windows中创建)中,读取的字符串中有'\ r \ n'字符。谢谢你,Yonatan。 – user1456524