이진 파일 읽기 및 각 바이트 반복
파이썬에서 바이너리 파일을 읽고 해당 파일의 각 바이트를 반복하는 방법은 무엇입니까?
파이썬 2.4 및 이전
f = open("myfile", "rb")
try:
byte = f.read(1)
while byte != "":
# Do stuff with byte.
byte = f.read(1)
finally:
f.close()
파이썬 2.5-2.7
with open("myfile", "rb") as f:
byte = f.read(1)
while byte != "":
# Do stuff with byte.
byte = f.read(1)
with 문은 2.5 이하의 Python 버전에서는 사용할 수 없습니다. v 2.5에서 사용하려면 가져와야합니다.
from __future__ import with_statement
2.6에서는 필요하지 않습니다.
파이썬 3
파이썬 3에서는 약간 다릅니다. 바이트 모드의 스트림에서 더 이상 원시 문자를 가져 오지 않고 바이트 객체를 가져 오므로 조건을 변경해야합니다.
with open("myfile", "rb") as f:
byte = f.read(1)
while byte != b"":
# Do stuff with byte.
byte = f.read(1)
또는 benhoyt가 말한 것처럼 같지 않은 것을 건너 뛰고 b""
거짓으로 평가 되는 사실을 이용하십시오 . 따라서 코드를 변경하지 않고 2.6과 3.x 사이에서 호환됩니다. 바이트 모드에서 텍스트 또는 그 반대로 전환하면 조건을 변경하지 않아도됩니다.
with open("myfile", "rb") as f:
byte = f.read(1)
while byte:
# Do stuff with byte.
byte = f.read(1)
이 생성기는 파일에서 바이트를 생성하여 파일을 청크로 읽습니다.
def bytes_from_file(filename, chunksize=8192):
with open(filename, "rb") as f:
while True:
chunk = f.read(chunksize)
if chunk:
for b in chunk:
yield b
else:
break
# example:
for b in bytes_from_file('filename'):
do_stuff_with(b)
반복자 와 생성기 에 대한 정보는 Python 문서를 참조하십시오 .
파일이 너무 커서 메모리에 보관하는 것이 문제가되지 않는 경우 :
bytes_read = open("filename", "rb").read()
for b in bytes_read:
process_byte(b)
여기서 process_byte는 전달 된 바이트에서 수행하려는 일부 조작을 나타냅니다.
한 번에 청크를 처리하려는 경우 :
file = open("filename", "rb")
try:
bytes_read = file.read(CHUNKSIZE)
while bytes_read:
for b in bytes_read:
process_byte(b)
bytes_read = file.read(CHUNKSIZE)
finally:
file.close()
버퍼링을 무시하고 한 번에 한 바이트 씩 파일을 읽으려면 두 개의 인수 iter(callable, sentinel)
내장 함수를 사용할 수 있습니다 .
with open(filename, 'rb') as file:
for byte in iter(lambda: file.read(1), b''):
# Do stuff with byte
file.read(1)
아무것도 반환하지 않을 때까지 호출 합니다 b''
(빈 바이트 열). 대용량 파일의 경우 메모리가 무제한으로 증가하지 않습니다. 당신은 전달할 수 buffering=0
에 open()
버퍼링을 사용하지, - 그것은 단지 한 바이트가 반복 (느린) 당 읽도록 보장한다.
with
-statement는 아래 코드에서 예외가 발생하는 경우를 포함하여 파일을 자동으로 닫습니다.
기본적으로 내부 버퍼링이 있지만 한 번에 1 바이트를 처리하는 것은 여전히 비효율적입니다. 예를 들어 blackhole.py
다음은 제공된 모든 것을 먹는 유틸리티입니다.
#!/usr/bin/env python3
"""Discard all input. `cat > /dev/null` analog."""
import sys
from functools import partial
from collections import deque
chunksize = int(sys.argv[1]) if len(sys.argv) > 1 else (1 << 15)
deque(iter(partial(sys.stdin.detach().read, chunksize), b''), maxlen=0)
예:
$ dd if=/dev/zero bs=1M count=1000 | python3 blackhole.py
그것은 처리 ~ 1.5 GB / s의 경우 chunksize == 32768
내 컴퓨터 만에 ~ 7.5 MB / s의 경우 chunksize == 1
. 즉, 한 번에 1 바이트를 읽는 것이 200 배 느립니다. 한 번에 둘 이상의 바이트를 사용하도록 처리를 다시 작성할 수 있고 성능이 필요한 경우이를 고려 하십시오.
mmap
파일과 bytearray
파일 객체를 동시에 취급 할 수 있습니다 . 두 인터페이스에 모두 액세스해야하는 경우 전체 파일을 메모리에로드하는 대신 사용할 수 있습니다. 특히 일반 for
루프를 사용하여 메모리 매핑 파일에서 한 번에 한 바이트 씩 반복 할 수 있습니다 .
from mmap import ACCESS_READ, mmap
with open(filename, 'rb', 0) as f, mmap(f.fileno(), 0, access=ACCESS_READ) as s:
for byte in s: # length is equal to the current file size
# Do stuff with byte
mmap
슬라이스 표기법을 지원합니다. 예를 들어 position에서 시작하는 파일에서 바이트를 mm[i:i+len]
반환 len
합니다 i
. 컨텍스트 관리자 프로토콜은 Python 3.2 이전에는 지원되지 않습니다. mm.close()
이 경우 명시 적 으로 호출해야합니다 . 를 사용하여 각 바이트를 반복 mmap
하면보다 많은 메모리 를 소비 file.read(1)
하지만 mmap
훨씬 빠릅니다.
chrispy, Skurmedel, Ben Hoyt 및 Peter Hansen의 모든 훌륭한 요점을 요약하면 이진 파일을 한 번에 한 바이트 씩 처리하는 최적의 솔루션입니다.
with open("myfile", "rb") as f:
while True:
byte = f.read(1)
if not byte:
break
do_stuff_with(ord(byte))
파이썬 버전 2.6 이상의 경우 :
- 파이썬 버퍼 내부-청크를 읽을 필요가 없습니다.
- 건조 원리-판독 라인을 반복하지 마십시오
- with 문은 깨끗한 파일을 닫습니다.
- 더 이상 바이트가 없으면 'byte'는 false로 평가됩니다 (바이트가 0이 아닌 경우)
또는 속도 향상을 위해 JF Sebastians 솔루션을 사용하십시오.
from functools import partial
with open(filename, 'rb') as file:
for byte in iter(partial(file.read, 1), b''):
# Do stuff with byte
또는 codeape에 의해 입증 된 것과 같은 생성기 함수로 사용하려는 경우 :
def bytes_from_file(filename):
with open(filename, "rb") as f:
while True:
byte = f.read(1)
if not byte:
break
yield(ord(byte))
# example:
for b in bytes_from_file('filename'):
do_stuff_with(b)
파이썬에서 이진 파일을 읽고 각 바이트를 반복
Python 3.5의 새로운 기능은 pathlib
모듈에서 파일을 바이트 단위로 읽는 편리한 방법을 제공하므로 바이트를 반복 할 수 있습니다. 나는 이것이 괜찮은 (빠르고 더러운 경우) 대답이라고 생각합니다.
import pathlib
for byte in pathlib.Path(path).read_bytes():
print(byte)
이것이 유일한 답변이라는 점에 흥미가 pathlib
있습니다.
파이썬 2에서는 Vinay Sajip이 제안한 것처럼 아마도 이렇게 할 것입니다.
with open(path, 'b') as file:
for byte in file.read():
print(byte)
파일이 메모리에서 반복하기에 너무 큰 경우 iter
에는 callable, sentinel
서명이 있는 함수 ( Python 2 버전)를 사용하여 관용적으로 청크를 만들 수 있습니다 .
with open(path, 'b') as file:
callable = lambda: file.read(1024)
sentinel = bytes() # or b''
for chunk in iter(callable, sentinel):
for byte in chunk:
print(byte)
(몇 가지 다른 답변이 이것을 언급하지만 합리적인 읽기 크기를 제공하는 사람은 거의 없습니다.)
큰 파일 또는 버퍼 / 대화 형 읽기에 대한 모범 사례
Python 3.5 이상에 대한 표준 라이브러리의 관용적 사용을 포함하여이를 수행하는 함수를 만들어 봅시다.
from pathlib import Path
from functools import partial
from io import DEFAULT_BUFFER_SIZE
def file_byte_iterator(path):
"""given a path, return an iterator over the file
that lazily loads the file
"""
path = Path(path)
with path.open('rb') as file:
reader = partial(file.read1, DEFAULT_BUFFER_SIZE)
file_iterator = iter(reader, bytes())
for chunk in file_iterator:
for byte in chunk:
yield byte
우리는 사용 file.read1
합니다. file.read
요청 된 모든 바이트를 얻을 때까지 또는 EOF
. file.read1
차단을 피할 수 있으며 이로 인해 더 빨리 돌아올 수 있습니다. 다른 답변들도 이것을 언급하지 않습니다.
모범 사례 사용법 시연 :
메가 바이트 (실제로 mebibyte)의 의사 난수 데이터로 파일을 만들어 봅시다 :
import random
import pathlib
path = 'pseudorandom_bytes'
pathobj = pathlib.Path(path)
pathobj.write_bytes(
bytes(random.randint(0, 255) for _ in range(2**20)))
이제 그것을 반복하고 메모리에 구체화합시다.
>>> l = list(file_byte_iterator(path))
>>> len(l)
1048576
데이터의 모든 부분 (예 : 마지막 100 바이트와 처음 100 바이트)를 검사 할 수 있습니다.
>>> l[-100:]
[208, 5, 156, 186, 58, 107, 24, 12, 75, 15, 1, 252, 216, 183, 235, 6, 136, 50, 222, 218, 7, 65, 234, 129, 240, 195, 165, 215, 245, 201, 222, 95, 87, 71, 232, 235, 36, 224, 190, 185, 12, 40, 131, 54, 79, 93, 210, 6, 154, 184, 82, 222, 80, 141, 117, 110, 254, 82, 29, 166, 91, 42, 232, 72, 231, 235, 33, 180, 238, 29, 61, 250, 38, 86, 120, 38, 49, 141, 17, 190, 191, 107, 95, 223, 222, 162, 116, 153, 232, 85, 100, 97, 41, 61, 219, 233, 237, 55, 246, 181]
>>> l[:100]
[28, 172, 79, 126, 36, 99, 103, 191, 146, 225, 24, 48, 113, 187, 48, 185, 31, 142, 216, 187, 27, 146, 215, 61, 111, 218, 171, 4, 160, 250, 110, 51, 128, 106, 3, 10, 116, 123, 128, 31, 73, 152, 58, 49, 184, 223, 17, 176, 166, 195, 6, 35, 206, 206, 39, 231, 89, 249, 21, 112, 168, 4, 88, 169, 215, 132, 255, 168, 129, 127, 60, 252, 244, 160, 80, 155, 246, 147, 234, 227, 157, 137, 101, 84, 115, 103, 77, 44, 84, 134, 140, 77, 224, 176, 242, 254, 171, 115, 193, 29]
이진 파일을 한 줄씩 반복하지 마십시오
다음을 수행하지 마십시오-이것은 줄 바꿈 문자가 될 때까지 임의의 크기의 청크를 가져옵니다. 청크가 너무 작거나 너무 클 때 너무 느립니다.
with open(path, 'rb') as file:
for chunk in file: # text newline iteration - not for bytes
for byte in chunk:
yield byte
위의 내용은 의미 적으로 사람이 읽을 수있는 텍스트 파일 (일반 텍스트, 코드, 마크 업, 마크 다운 등 ... 본질적으로 ascii, utf, latin 등 ... 인코딩 된 것)에만 적합합니다.
파이썬 3, 모든 파일을 한번에 읽으십시오 :
with open("filename", "rb") as binary_file:
# Read the whole file at once
data = binary_file.read()
print(data)
data
변수를 사용하여 원하는 것을 반복 할 수 있습니다 .
위의 모든 것을 시도하고 @Aaron Hall의 답변을 사용한 후 Window 10, 8Gb RAM 및 Python 3.5 32 비트를 실행하는 컴퓨터에서 ~ 90 Mb 파일에 대한 메모리 오류가 발생했습니다. 동료가 numpy
대신 사용하도록 권장했으며 놀라운 일이 아닙니다.
지금까지 테스트 한 전체 바이너리 파일을 읽는 가장 빠른 방법은 다음과 같습니다.
import numpy as np
file = "binary_file.bin"
data = np.fromfile(file, 'u1')
지금까지 다른 방법보다 훨씬 빠르게 그것이 누군가를 돕기를 바랍니다!
읽을 바이너리 데이터가 많은 경우 struct 모듈 을 고려할 수 있습니다 . "C와 Python 유형 간"변환으로 문서화되었지만 바이트는 바이트이며 C 유형으로 작성된 것인지는 중요하지 않습니다. 예를 들어, 이진 데이터에 2 바이트 정수 2 개와 4 바이트 정수 1 개가 포함 된 경우 다음과 같이 읽을 수 있습니다 ( struct
문서 에서 가져온 예 ).
>>> struct.unpack('hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
파일의 내용을 명시 적으로 반복하는 것보다이 방법이 더 편리하거나 빠르거나 둘 다있을 수 있습니다.
빠른 것을 찾고 있다면 몇 년 동안 사용해온 방법이 있습니다.
from array import array
with open( path, 'rb' ) as file:
data = array( 'B', file.read() ) # buffer the file
# evaluate it's data
for byte in data:
v = byte # int value
c = chr(byte)
int 대신 chars를 반복하려면 data = file.read()
py3의 bytes () 객체 인을 사용하면됩니다.
참고 URL : https://stackoverflow.com/questions/1035340/reading-binary-file-and-looping-over-each-byte
'Programming' 카테고리의 다른 글
특성 함수를 재정의하고 재정의 된 함수에서 호출하는 방법은 무엇입니까? (0) | 2020.03.03 |
---|---|
복잡한 Git 브랜치 이름으로 모든 Git 명령이 중단됨 (0) | 2020.03.03 |
파이썬에서 .mat 파일 읽기 (0) | 2020.03.03 |
JavaScript에서 span 요소의 텍스트를 변경하는 방법 (0) | 2020.03.03 |
Linux에서 pthread_create에 대한 정의되지 않은 참조 (0) | 2020.03.03 |