끝에서 x 바이트까지 파일 객체에서 블록 읽기

Nov 22 2020

루프에서 64KB 청크를 읽고 처리해야하지만 파일 끝에서 16 바이트를 빼면 중지됩니다 . 마지막 16 바이트는 tag메타 데이터입니다.

파일이 너무 커서 RAM에서 모두 읽을 수 없습니다.

내가 찾은 모든 솔루션은 약간 서 투르거나 비 파이썬 적입니다.

with open('myfile', 'rb') as f:
    while True:
        block = f.read(65536)
        if not block:
            break
        process_block(block)

이면 16 <= len(block) < 65536쉽습니다 : 이제까지의 마지막 블록입니다. 그래서 useful_data = block[:-16]tag = block[-16:]

이면 세 가지를 의미 len(block) == 65536 있습니다. 전체 블록이 유용한 데이터라는 것입니다. 또는이 64KB 블록이 실제로 마지막 블록 이므로 useful_data = block[:-16]tag = block[-16:]. 또는이 64KB 블록 뒤에 몇 바이트 (3 바이트라고 가정 해 보겠습니다)의 또 다른 블록이 따라 오므로이 경우 : useful_data = block[:-13]tag = block[-13:] + last_block[:3].

이 모든 경우를 구분하는 것보다 더 좋은 방법으로이 문제를 처리하는 방법은 무엇입니까?

노트 :

  • 솔루션은로 열린 파일에 대해 작동해야 open(...)하지만 io.BytesIO()객체에 대해서도 작동 하거나 멀리있는 SFTP 열린 파일 (사용 pysftp)에 대해서도 작동해야합니다 .

  • 나는 파일 객체 크기를 얻는 것에 대해 생각하고 있었다.

    f.seek(0,2)
    length = f.tell()
    f.seek(0)
    

    그런 다음 각각

    block = f.read(65536)
    

    으로 끝이 멀다는 것을 알 수 length - f.tell()있지만 전체 솔루션이 매우 우아하게 보이지는 않습니다.

답변

1 LiorCohen Nov 22 2020 at 20:31

모든 반복에서 읽을 수 있습니다. min(65536, L-f.tell()-16)

이 같은:

from pathlib import Path

L = Path('myfile').stat().st_size

with open('myfile', 'rb') as f:
    while True:    
        to_read_length = min(65536, L-f.tell()-16)
        block = f.read(to_read_length)
        process_block(block)
        if f.tell() == L-16
            break

이것을 실행하지 않았지만 요점을 이해하기를 바랍니다.

1 PresidentJamesK.Polk Nov 23 2020 at 00:16

다음 메서드 f.read()는 스트림 끝 (EOS)에서 빈 바이트 개체를 반환 한다는 사실에만 의존합니다 . 따라서 그것은 단순히 대체하여 소켓을 채택 할 수 f.read()와 함께 s.recv().

def read_all_but_last16(f):
    rand = random.Random()  #  just for testing
    buf = b''
    while True:
        bytes_read = f.read(rand.randint(1, 40))  # just for testing
        # bytes_read = f.read(65536)
        buf += bytes_read
        if not bytes_read:
            break
        process_block(buf[:-16])
        buf = buf[-16:]
    verify(buf[-16:])

bufEOS 가 끝날 때까지 항상 16 바이트를 남겨두고 마지막으로 마지막 16 바이트를 처리하는 방식으로 작동 합니다. 최소 17 바이트가 없으면 빈 바이트 개체 bufbuf[:-16]반환합니다.