使用python从大型二进制文件中删除一系列字符

时间:2008-10-21 10:21:47

标签: python numpy binaryfiles

我想从python中的二进制文件中修剪相同值的长序列。一种简单的方法是简单地读取文件并使用re.sub替换不需要的序列。这当然不适用于大型二进制文件。可以用像numpy这样的东西吗?

6 个答案:

答案 0 :(得分:4)

如果你没有内存来做open("big.file").read(),那么numpy将不会真正帮助..它使用与python变量相同的内存(如果你有1GB的RAM,你只能加载1GB的数据)变成numpy)

解决方案很简单 - 以块为单位读取文件.. f = open("big.file", "rb"),然后执行一系列f.read(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

这不是最有效的方式,但它可以工作,而不需要在内存中保留文件的副本(或两个)。

答案 1 :(得分:2)

如果内存中有两个副本,那么您可以轻松制作副本。第二个副本是压缩版本。当然,您可以使用numpy,但您也可以使用array包。此外,您可以将大二进制对象视为字节字符串并直接对其进行操作。

听起来您的文件可能真的大,并且您无法将两个副本放入内存中。 (你没有提供很多细节,所以这只是一个猜测。)你必须在块中进行压缩。你将读入一个块,对该块进行一些处理并将其写出来。同样,numpy,数组或简单的字节串将正常工作。

答案 2 :(得分:1)

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()

答案 3 :(得分:1)

除非替换字符串的大小不同,否则AJMayorga的建议很好。或者替换字符串位于块的末尾。

我这样修好了:

def ReplaceSequence(inFilename, outFilename, oldSeq, newSeq):
    inputFile  = open(inFilename, "rb")
    outputFile = open(outFilename, "wb")

data = ""
chunk = 1024

oldSeqLen = len(oldSeq)

while 1:
    data = inputFile.read(chunk)

    dataSize = len(data)
    seekLen= dataSize - data.rfind(oldSeq) - oldSeqLen
    if seekLen > oldSeqLen:
        seekLen = oldSeqLen

    data = data.replace(oldSeq, newSeq)
    outputFile.write(data)
    inputFile.seek(-seekLen, 1) 
    outputFile.seek(-seekLen, 1)

    if dataSize < chunk:
        break

inputFile.close()
outputFile.close()

答案 4 :(得分:0)

您需要更准确地提出问题。你知道你想要提前修剪的价值吗?

假设你这样做,我可能会使用subprocess搜索匹配的部分来运行“fgrep -o -b <search string>”,然后使用python file对象的{{}来更改文件的相关部分。 1}},seekread方法。

答案 5 :(得分:0)

这个基于生成器的版本一次只能在文件内容中保留一个字符。

请注意,我的字面意思是你的问题标题 - 你希望将同一个字符的运行减少到一个字符。一般来说,为了替换模式,这不起作用:

import StringIO

def gen_chars(stream):
   while True:
      ch = stream.read(1)
      if ch: 
         yield ch
      else:
         break

def gen_unique_chars(stream):
   lastchar = ''
   for char in gen_chars(stream):
      if char != lastchar:
         yield char
      lastchar=char

def remove_seq(infile, outfile):
   for ch in gen_unique_chars(infile):
      outfile.write(ch)

# Represents a file open for reading
infile  = StringIO.StringIO("1122233333444555")

# Represents a file open for writing
outfile = StringIO.StringIO()

# Will print "12345"
remove_seq(infile, outfile)
outfile.seek(0)
print outfile.read()