使用Python从大型二进制文件中删除字符序列
我想在Python中从一个二进制文件中去掉连续的相同值。一个简单的方法就是把文件读进来,然后用re.sub来替换掉那些不需要的连续值。不过,这种方法在处理大文件时就不太好用了。有没有什么办法可以用numpy来实现呢?
6 个回答
dbr的解决方案是个好主意,但有点复杂。其实你只需要在读取下一个数据块之前,把文件指针回退到你要查找的序列的长度就可以了。
def ReplaceSequence(inFilename, outFilename, oldSeq, newSeq):
inputFile = open(inFilename, "rb")
outputFile = open(outFilename, "wb")
data = ""
chunk = 1024
while 1:
data = inputFile.read(chunk)
data = data.replace(oldSeq, newSeq)
outputFile.write(data)
inputFile.seek(-len(oldSequence), 1)
outputFile.seek(-len(oldSequence), 1)
if len(data) < chunk:
break
inputFile.close()
outputFile.close()
如果你的内存能放下两个副本,那你就可以轻松地复制一个。第二个副本是压缩后的版本。没错,你可以用numpy来处理,但你也可以使用array这个包。此外,你还可以把你的大二进制对象当作一串字节来直接操作。
听起来你的文件可能真的很大,以至于内存放不下两个副本。(你没有提供很多细节,所以这只是个猜测。)你需要分块进行压缩。你会先读取一块数据,对这块数据进行处理,然后再写出去。再次强调,numpy、array或者简单的字节串都可以很好地完成这个任务。
如果你的电脑内存不够,无法执行 open("big.file").read()
这个操作,那么使用numpy也没什么用。因为numpy和Python的变量一样,都是用内存的。如果你的电脑只有1GB的内存,那你最多只能加载1GB的数据到numpy里。
解决办法很简单——分块读取文件。你可以用 f = open("big.file", "rb")
打开文件,然后用 f.read(500)
一次读取500个字节。读取完后,把这些内容处理完再写回到另一个文件里。这其实和在C语言中读写文件的方式差不多。
不过,这样做有个问题,就是如果你替换的内容模式错过了,就会出错。例如:
target_seq = "567"
input_file = "1234567890"
target_seq.read(5) # reads 12345, doesn't contain 567
target_seq.read(5) # reads 67890, doesn't contain 567
显而易见的解决办法是,从文件的第一个字符开始,检查 len(target_seq)
个字符,然后向前移动一个字符,再检查一次。
比如(伪代码!):
while cur_data != "":
seek_start = 0
chunk_size = len(target_seq)
input_file.seek(offset = seek_start, whence = 1) #whence=1 means seek from start of file (0 + offset)
cur_data = input_file.read(chunk_size) # reads 123
if target_seq == cur_data:
# Found it!
out_file.write("replacement_string")
else:
# not it, shove it in the new file
out_file.write(cur_data)
seek_start += 1
虽然这种方法不是最有效率的,但它能工作,而且不需要在内存中保留文件的副本(或者两个副本)。