2016-10-18 11 views
0

以下のコードでは、特別な構造を持つ大きなファイルを読み込みます。特に、同時に処理する必要がある2つのブロックがあります。代わりに、前後のファイルを探しているの私はmemoryviewに包まれたこれら二つのブロックをロードmemoryviewでバイナリファイルを読む

with open(abs_path, 'rb') as bsa_file: 
    # ... 
    # load the file record block to parse later 
    file_records_block = memoryview(bsa_file.read(file_records_block_size)) 
    # load the file names block 
    file_names_block = memoryview(bsa_file.read(total_file_name_length)) 
    # close the file 
file_records_index = names_record_index = 0 
for folder_record in folder_records: 
    name_size = struct.unpack_from('B', file_records_block, file_records_index)[0] 
    # discard null terminator below 
    folder_path = struct.unpack_from('%ds' % (name_size - 1), 
     file_records_block, file_records_index + 1)[0] 
    file_records_index += name_size + 1 
    for __ in xrange(folder_record.files_count): 
     file_name_len = 0 
     for b in file_names_block[names_record_index:]: 
      if b != '\x00': file_name_len += 1 
      else: break 
     file_name = unicode(struct.unpack_from('%ds' % file_name_len, 
      file_names_block,names_record_index)[0]) 
     names_record_index += file_name_len + 1 

呼び出し、ファイルが正しく解析されますが、それはmamoryviewインターフェイスの私の最初の使用だと私は右のそれを行うことを確認していません。 file_names_blockは、ヌルで終わるC文字列で見られるように構成されています。

  1. 私のトリックfile_names_block[names_record_index:]はmemoryviewマジックを使用していますか、またはいくつかのn^2スライスを作成しますか?ここでisliceを使用する必要がありますか?
  2. 私が見たように、私はヌルバイトを手動で探し、次にunpack_fromに進みます。しかし、私はHow to split a byte string into separate bytes in pythonで、メモリビューでcast()(docs?)を使うことができます。それを使ってバイト単位でビューを分割する方法はありますか?ちょうどsplit('\x00')に電話できますか?これはメモリ効率を維持するでしょうか?

(python 2の)これを行う正しい方法を理解していただければ幸いです。

+0

ここでは、メモリビューでは何も得られないと思います。 'struct'モジュールのようなメモリビューには、ヌルで終わる文字列のための特別な機能はありません。 –

答えて

1

memoryviewは、固定幅データ以外の機能を持たないため、ヌル文字で終了する文字列には何のメリットもありません。あなたにも代わりにここにbytes.split()を使用することがあります。

memoryview(ビューパラメータ以外の)余分なメモリを使用しませんが、キャストを使用した場合は、解析されたメモリ領域のための新しいネイティブオブジェクトを生成しないのスライス
file_names_block = bsa_file.read(total_file_name_length) 
file_names = file_names_block.split(b'\00') 

をシーケンス内の要素にアクセスしようとすると、

file_records_blockの解析にはmemoryviewを引き続き使用できます。これらの文字列の前には、スライスを使用する長さが付いています。ただ、インデックスを維持する必要はありませんあなたはfolder_path値を処理するように、メモリビューのバイトをスライスしておく:

for folder_record in folder_records: 
    name_size = file_records_block[0] # first byte is the length, indexing gives the integer 
    folder_path = file_records_block[1:name_size].tobytes() 
    file_records_block = file_records_block[name_size + 1:] # skip the null 

memoryviewbytesオブジェクトから供給されたため、インデックスは、あなたのバイトのための整数値を与えるであろう、与えられたスライスの.tobytes()には、そのセクションの新しいbytes文字列が与えられ、スライスを続けて次のループのために残りの部分を残すことができます。

+0

ありがとう本当に:)私は分割を使用して、 'del file_names_block'を追加することができたと思います。私はそれが 'file_records_block [name_size:]'であってはならないと思いますか? –

+1

@Mr_and_Mrs_D:ループの後に 'file_records_block.release()'を使用して、 'bytes'を解放することができます(これは、バッファのメモリがどれくらい速く解放されたのか疑問です)。オブジェクト。 –

+0

@Mr_and_Mrs_D:あなたが 'file_records_block [name_size:]'に関して何を求めているのかよくわかりません。 –

関連する問題