我有一个保存为 csv 文件的特征向量的巨大文件(1.2GB)。为了通过这些行,我创建了一个 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 一起工作得很好。
但后来我处理了这些特征并创建了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)字符串长度作为 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() 读取的字符串似乎是可读的。我怎样才能确定?)。
非常感谢您的帮助,包括解释、原因的想法以及可能的解决方案(或解决方法)。
谢谢你,约纳坦。