Удаление последовательности символов из большого двоичного файла с использованием Python - PullRequest
3 голосов
/ 21 октября 2008

Я хотел бы обрезать длинные последовательности одного и того же значения из двоичного файла в Python. Простой способ сделать это - просто прочитать файл и использовать re.sub для замены нежелательной последовательности. Это, конечно, не будет работать с большими двоичными файлами. Это может быть сделано в чем-то вроде numpy?

Ответы [ 6 ]

4 голосов
/ 21 октября 2008

Если у вас нет памяти для выполнения open("big.file").read(), то numpy на самом деле не поможет .. Он использует ту же память, что и переменные python (если у вас 1 ГБ ОЗУ, вы можете загрузить только 1 ГБ данных в 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

Это не совсем эффективный способ, но он будет работать и не потребует сохранения копии файла в памяти (или двух).

2 голосов
/ 21 октября 2008

Если две копии помещаются в памяти, вы можете легко сделать копию. Вторая копия - сжатая версия. Конечно, вы можете использовать numpy, но вы также можете использовать пакет array . Кроме того, вы можете рассматривать ваш большой двоичный объект как строку байтов и манипулировать им напрямую.

Похоже, ваш файл может быть ДЕЙСТВИТЕЛЬНО большой, и вы не можете поместить две копии в память. (Вы не предоставили много подробностей, так что это всего лишь предположение.) Вам придется делать сжатие кусками. Вы будете читать в чанке, делать некоторую обработку этого чанка и записывать его. Опять же, NumPy, массив или простая строка байтов будут работать нормально.

1 голос
/ 28 ноября 2012

Предложение 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()
1 голос
/ 17 июня 2009

Решение 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()
0 голосов
/ 17 июня 2009

Эта версия на основе генератора будет одновременно хранить в памяти ровно один символ содержимого файла.

Обратите внимание, что я понимаю ваш вопрос в буквальном смысле - вы хотите уменьшить количество повторений одного и того же символа до одного символа. Для замены шаблонов в целом это не работает:

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()
0 голосов
/ 21 октября 2008

Вы должны уточнить свой вопрос. Знаете ли вы значения, которые вы хотите обрезать заранее?

Если вы это сделаете, я, вероятно, буду искать соответствующие разделы, используя subprocess, чтобы запустить "fgrep -o -b <search string>", а затем изменить соответствующие разделы файла, используя seek, *1006* объекта python file и write методы.

...