Pregunta

Me gustaría recortar secuencias largas del mismo valor de un archivo binario en Python.Una forma sencilla de hacerlo es simplemente leer el archivo y usar re.sub para reemplazar la secuencia no deseada.Por supuesto, esto no funcionará en archivos binarios grandes.¿Se puede hacer en algo como numpy?

¿Fue útil?

Solución

Si no tiene memoria para hacer open("big.file").read(), numpy realmente no ayudará. Utiliza la misma memoria que las variables de Python (si tiene 1 GB de RAM, solo puede cargar 1 GB de datos en numpy )

La solución es simple: lea el archivo en fragmentos .. f = open("big.file", "rb"), luego haga una serie de f.read(500), elimine la secuencia y escríbala en otro objeto de archivo. Prácticamente cómo haces para leer / escribir archivos en C ..

El problema es si pierde el patrón que está reemplazando ... Por ejemplo:

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

La solución obvia es comenzar con el primer carácter del archivo, verificar len(target_seq) caracteres, luego avanzar un carácter, verificar hacia adelante nuevamente.

Por ejemplo (¡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

No es exactamente la forma más eficiente, pero funcionará, y no requiere guardar una copia del archivo en la memoria (o dos).

Otros consejos

Si dos copias caben en la memoria, puede hacer una copia fácilmente. La segunda copia es la versión comprimida. Claro, puede usar numpy, pero también puede usar la matriz paquete. Además, puede tratar su objeto binario grande como una cadena de bytes y manipularlo directamente.

Parece que su archivo puede ser REALMENTE grande y no puede guardar dos copias en la memoria. (No proporcionaste muchos detalles, así que esto es solo una suposición). Tendrás que hacer tu compresión en trozos. Leerá en un fragmento, procesará un poco en ese fragmento y lo escribirá. Nuevamente, numpy, array o cadena simple de bytes funcionará bien.

La solución de dbr es una buena idea, pero un poco demasiado complicado, todo lo que realmente tiene que hacer es rebobinar el puntero del archivo la longitud de la secuencia que está buscando, antes de leer su próximo fragmento.

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

La sugerencia de AJMayorga está bien a menos que los tamaños de las cadenas de reemplazo sean diferentes. O la cadena de reemplazo está al final del fragmento.

Lo arreglé así:

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

Necesitas hacer tu pregunta más precisa.¿Conoce los valores que desea recortar de antemano?

Suponiendo que así sea, probablemente buscaría las secciones coincidentes usando subprocess correr "fgrep -o -b <search string>" y luego cambie las secciones relevantes del archivo usando Python file objetos seek, read y write métodos.

Esta versión basada en generador mantendrá exactamente un carácter del contenido del archivo en la memoria a la vez.

Tenga en cuenta que estoy tomando el título de su pregunta literalmente: desea reducir las ejecuciones del mismo carácter a un solo carácter. Para reemplazar patrones en general, esto no funciona:

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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top