Frage

Ich mag lange Sequenzen mit dem gleichen Wert aus einer Binärdatei in Python trimmen. Eine einfache Möglichkeit, es zu tun liest einfach in der Datei und mit re.sub der unerwünschten Folge zu ersetzen. Dies wird natürlich nicht auf große binäre Dateien. Kann es in so etwas wie numpy getan werden?

War es hilfreich?

Lösung

Wenn Sie nicht über den Speicher open("big.file").read() zu tun, dann wirklich numpy nicht helfen .. Es verwendet den gleichen Speicher wie Python Variablen haben (wenn Sie 1 GB RAM haben, können Sie nur 1 GB Daten in numpy laden)

Die Lösung ist einfach - die Datei in Stücke lesen .. f = open("big.file", "rb"), dann eine Reihe von f.read(500), die Sequenz entfernen und schreiben Sie es heraus in ein anderes Dateiobjekt zurück. Ziemlich viel, wie Sie tun, Datei lesen / in C zu schreiben ..

Das Problem ist dann, wenn Sie das Muster, das Sie ersetzen verpassen .. Zum Beispiel:

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

Die offensichtliche Lösung ist mit dem ersten Zeichen in der Datei, überprüft len(target_seq) Zeichen, dann gehen Sie ein Zeichen vorwärts, überprüft wieder nach vorne beginnen.

Zum Beispiel (Pseudo-Code!):

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

Es ist nicht gerade die effizienteste Art und Weise, aber es wird funktionieren, und erfordert nicht eine Kopie der Datei im Speicher (oder zwei) zu halten.

Andere Tipps

Wenn zwei Kopien in den Speicher passen, dann können Sie ganz einfach eine Kopie. Die zweite Kopie ist die komprimierte Version. Sicher, können Sie numpy, aber Sie können auch die Array Paket. Darüber hinaus können Sie Ihr großes binäres Objekt als eine Kette von Bytes behandeln und es direkt manipulieren.

Es klingt wie Ihre Datei sein kann wirklich groß, und man kann nicht zwei Kopien in den Speicher passen. (Sie haben nicht viele Details liefern, so ist dies nur eine Vermutung.) Sie werden Ihre Kompression in Stücke zu tun haben. Sie werden in einem Stück lesen, auf diesem Brocken einige Verarbeitung tun und schreiben Sie es heraus. Auch hier wird numpy, Array oder einfache Kette von Bytes funktionieren.

dbr-Lösung ist eine gute Idee, aber ein bisschen zu kompliziert alles, was Sie wirklich tun müssen, ist die Datei zurückspulen die Länge des Sequenzzeiger Sie suchen, bevor Sie Ihren nächsten Brocken lesen.

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 Vorschlag ist in Ordnung, es sei denn, die Größen der Ersatzzeichenfolgen unterschiedlich sind. Oder die Ersatzzeichenfolge ist am Ende des Blocks.

ich es wie folgt festgelegt:

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

Sie benötigen eine Frage präziser zu machen. Haben Sie die Werte wissen Sie vor der Zeit trimmen wollen?

Angenommen, Sie tun, würde ich wahrscheinlich für die passenden Abschnitte mit subprocess suchen „fgrep -o -b <search string>“ laufen und dann den entsprechenden Abschnitten der Datei ändert den Python file Objekts seek, read und write Methoden verwenden.

Dieser Generator-basierte Version hält genau ein Zeichen des Dateiinhalts im Speicher auf einmal.

Beachten Sie, dass ich Ihre Frage Titel ganz wörtlich nehme - wollen Sie läuft mit dem gleichen Charakter auf ein einzelnes Zeichen zu reduzieren. Für Muster im Allgemeinen ersetzen, funktioniert das nicht:

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()
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top