Python のバイナリ ファイルから同じ値の長いシーケンスをトリミングしたいと思います。これを行う簡単な方法は、単にファイルを読み込んで re.sub を使用して不要なシーケンスを置き換えることです。もちろん、これは大きなバイナリ ファイルでは機能しません。numpyのようなものでそれを行うことはできますか?
6 に答える
実行するメモリがない場合open("big.file").read()
、numpy は本当に役に立ちません。Python 変数と同じメモリを使用します (1GB の RAM がある場合、1GB のデータしか 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)
、次に 1 文字進み、もう一度前方をチェックすることです。
例(疑似コード!):
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
これは正確には最も効率的な方法ではありませんが、機能し、ファイルのコピーをメモリ (または 2 つ) に保持する必要はありません。
2 つのコピーがメモリに収まる場合は、簡単にコピーを作成できます。2 番目のコピーは圧縮バージョンです。確かに、numpy を使用できますが、arrayパッケージも使用できます。さらに、ビッグ バイナリ オブジェクトをバイトの文字列として扱い、直接操作することもできます。
ファイルが非常に大きく、2 つのコピーをメモリに収めることができないようです。(多くの詳細を提供しなかったので、これは単なる推測です。) チャンクで圧縮を行う必要があります。チャンクを読み取り、そのチャンクで何らかの処理を行い、それを書き出します。ここでも、numpy、配列、または単純なバイト文字列が正常に機能します。
交換用の弦のサイズが異なる場合を除いて、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()
このジェネレーター ベースのバージョンでは、一度にファイル コンテンツの 1 文字だけがメモリに保持されます。
私はあなたの質問のタイトルを文字通りに取っていることに注意してください.同じ文字の実行を1文字に減らしたい. 一般的なパターンの置換では、これは機能しません。
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()
質問をより正確にする必要があります。トリムする値を事前に把握していますか?
あなたがそうしていると仮定すると、おそらくsubprocess
" " を実行して一致するセクションを検索し、fgrep -o -b <search string>
次に pythonfile
オブジェクトのseek
およびread
メソッドwrite
を使用してファイルの関連セクションを変更します。