2016-10-18 2 views
0

아래 코드에서 대용량 파일을 읽습니다.이 파일은 특히 동시에 처리해야하는 두 개의 블록 중에서 특별한 구조를가집니다. 대신 앞뒤로 파일 추구의 내가 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은 null로 끝나는 c 문자열에서 볼 수 있도록 구성됩니다.

  1. 내 트릭 file_names_block[names_record_index:]은 (는) memoryview 마법을 사용합니까? 아니면 n^2 조각을 만드시겠습니까? 여기 islice을 사용해야합니까?
  2. 본 것처럼 나는 null 바이트를 수동으로 찾은 다음 unpack_from으로 진행합니다. 그러나 나는 cast() (docs?)을 메모리 뷰에서 사용할 수 있다고 How to split a byte string into separate bytes in python에서 읽었습니다. 그 방법을 사용하여 (또는 다른 트릭) 바이트 단위로 뷰를 분할 할 수 있습니까? 방금 split('\x00')에 전화 할 수 있습니까? 이것은 메모리 효율성을 유지합니까?

(파이썬 2에서) 올바른 방법에 대한 통찰력을 얻었습니다.

+0

나는 memoryviews가 당신에게 아무것도주지 않는다고 생각하지 않는다; 'struct' 모듈과 같은 메모리 뷰는 널 종료 문자열을위한 특별한 기능을 가지고 있지 않습니다. –

답변

1

memoryview은 고정 너비 데이터 외에 다른 기능을 제공하지 않으므로 Null 종료 문자열에 이점이 없습니다. 당신은뿐만 아니라 여기 bytes.split()을 사용할 수 있습니다 :

memoryview이 (뷰 매개 변수 이외의) 추가 메모리를 사용하지 않습니다 칼자국
file_names_block = bsa_file.read(total_file_name_length) 
file_names = file_names_block.split(b'\00') 

,하지만 당신은 구문 분석 메모리 영역에 대한 새로운 네이티브 객체를 생성 할 캐스트를 사용하는 경우 시퀀스에서 요소에 액세스하려고 할 때.

구문 분석에는 여전히 memoryview을 사용할 수 있습니다. 그 문자열에는 접두사가 붙어서 길이를 쳐서 조각 내기를 사용할 수 있습니다. memoryviewbytes 객체에서 공급 되었기 때문에

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 

가, 색인 바이트 당신에게 정수 값를 제공합니다 : 당신이 folder_path 값을 처리하는대로 그냥 메모리보기의 바이트를 얇게 유지, 인덱스를 유지 할 필요가 없습니다 주어진 슬라이스의 .tobytes()은 해당 섹션에 대한 새로운 bytes 문자열을 제공하므로 슬라이스를 계속하여 다음 루프의 나머지 부분을 남겨 둘 수 있습니다.

+0

정말로 감사합니다 :) 저는 split을 사용하여'del file_names_block'을 추가 할 수있었습니다. 그 중 하나에 관해서는 그것이'file_records_block [name_size :]'가되어서는 안된다고 생각하십니까? 나는이 마지막 작업 후에 메모리가 얼마나 빨리 빠져 있는지 궁금하다. 그러나 이것은 C 녀석들을위한 것이다. :) –

+1

@Mr_and_Mrs_D : 루프 뒤에서'file_records_block.release()'를 사용하여'bytes'를 해제 할 수있다. 목적. –

+0

@Mr_and_Mrs_D : 당신이'file_records_block [name_size :]'에 대해서 무엇을 묻고 있는지 잘 모르겠다. .. –