Removendo uma sequência de caracteres de um arquivo binário grande usando python

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

  •  03-07-2019
  •  | 
  •  

Pergunta

Gostaria de cortar longas sequências do mesmo valor de um arquivo binário em python.Uma maneira simples de fazer isso é simplesmente ler o arquivo e usar re.sub para substituir a sequência indesejada.É claro que isso não funcionará em arquivos binários grandes.Isso pode ser feito em algo como numpy?

Foi útil?

Solução

Se você não tem memória para fazer open("big.file").read(), então numpy realmente não vai ajudar ..Ele usa a mesma memória que as variáveis ​​python (se você tiver 1 GB de RAM, poderá carregar apenas 1 GB de dados em numpy)

A solução é simples - leia o arquivo em pedaços. f = open("big.file", "rb"), então faça uma série de f.read(500), remova a sequência e grave-a novamente em outro objeto de arquivo.Praticamente como você faz leitura/gravação de arquivos em C.

O problema então é se você perder o padrão que está substituindo.Por exemplo:

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

A solução óbvia é começar no primeiro caractere do arquivo, verificar len(target_seq) caracteres, avance um caractere e verifique novamente.

Por exemplo (pseudocódigo!):

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

Não é exatamente a maneira mais eficiente, mas funcionará e não exigirá manter uma cópia do arquivo na memória (ou duas).

Outras dicas

Se duas cópias se encaixam na memória, você poderá facilmente fazer uma cópia. A segunda cópia é a versão compactada. Claro, você pode usar Numpy, mas também pode usar o variedade pacote. Além disso, você pode tratar seu grande objeto binário como uma sequência de bytes e manipulá -lo diretamente.

Parece que seu arquivo pode ser VERDADE Grande, e você não pode encaixar duas cópias na memória. (Você não forneceu muitos detalhes, então isso é apenas um palpite.) Você terá que fazer sua compactação em pedaços. Você lerá em um pedaço, fará algum processamento nesse pedaço e escrevê -lo. Novamente, Numpy, matriz ou cordas simples de bytes funcionarão bem.

A solução do DBR é uma boa ideia, mas um pouco complicado tudo o que você realmente precisa fazer é rebobinar o ponteiro do arquivo a duração da sequência que você está procurando, antes de ler seu próximo pedaço.

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 suggestion is fine unless the sizes of the replacement strings are different. Or the replacement string is at the end of the chunk.

I fixed it like this:

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

You need to make your question more precise. Do you know the values you want to trim ahead of time?

Assuming you do, I would probably search for the matching sections using subprocess to run "fgrep -o -b <search string>" and then change the relevant sections of the file using the python file object's seek, read and write methods.

This generator-based version will keep exactly one character of the file content in memory at a time.

Note that I am taking your question title quite literally - you want to reduce runs of the same character to a single character. For replacing patterns in general, this does not work:

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()
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top