Удаление последовательности символов из большого двоичного файла с использованием Python

StackOverflow https://stackoverflow.com/questions/221386

  •  03-07-2019
  •  | 
  •  

Вопрос

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

Это было полезно?

Решение

Если у вас нет памяти для выполнения 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

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

Другие советы

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

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

Решение 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()

Предложение 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()

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

Предполагая, что вы это сделаете, я, вероятно, буду искать соответствующие разделы, используя подпроцесс для запуска " fgrep -o -b < строка поиска > " а затем измените соответствующие разделы файла, используя методы search , read и write объекта python file . / р>

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

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

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()
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top