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

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

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
0
3 626
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

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

Похоже, ваш файл может быть В САМОМ ДЕЛЕ большого размера, и вы не можете разместить две копии в памяти. (Вы не предоставили много деталей, так что это всего лишь предположение.) Вам придется выполнять сжатие по частям. Вы будете читать фрагмент, обрабатывать его и записывать. Опять же, numpy, array или простая строка байтов будут работать нормально.

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

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

Ответ принят как подходящий

Если у вас нет памяти для работы с 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 будет какое-то автоматическое управление памятью для больших файлов - я не слишком знаком с этим.

bluegray 24.10.2008 16:00

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

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

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

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

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

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