我有一个巨大的文件(1.2GB)的特征向量保存为csv文件。 为了完成这些操作,我创建了一个python类,它将巨型文件中的批量行加载到内存中,一次一批。
为了让这个类知道文件中的确切读取位置以获得一批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可以很好用。
然后我处理了这些功能并创建了huge_file2(带有规范化功能),在我所做的这个类的帮助下。 接下来,当我想从huge_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();
主要的变化是偏移量I寄存器取自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'
这里有一些矛盾:当我在第67页的位置(根据fid.tell())一旦读取行是一件事并且在第二次(当fid.tell()再次报告我是位于字节67),读取的行是不同的。
我无法相信tell()和seek()将我放在所需位置以从所需行的开头读取。 另一方面,当我使用(使用giant_file1)字符串的长度作为seek()的参考时,我得到了正确的位置:
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。
答案 0 :(得分:2)
我认为你有换行问题。检查giant_file1.csv是否以\ n或\ r \ n结尾行。如果在文本模式下打开文件,该文件将返回以\ n结尾的行,并丢弃冗余\ r \ n。因此,当您查看返回的行的长度时,它将是实际文件位置的1(不仅消耗了\ n,而且消耗了\ r \ n)。当然,当你阅读更多行时,这些错误会累积起来。
解决方案是以二进制模式打开文件。在这种模式下,没有\ r \ n - &gt;减少,所以你的行长度与你的文件tell()查询保持一致。
我希望能为你解决这个问题 - 因为它很容易解决。祝你的项目好运,编码愉快!
答案 1 :(得分:0)
过去我必须做类似的事情,并在标准库中遇到一些名为linecache的东西。您可能也想查看它。