파이썬에서 EOF까지 루프하는 방법은 무엇입니까?
문제
파일과 같은 객체의 끝을 누르기 전까지는 반복해야하지만 "명백한 방법"을 찾지 못해서 무언가를 간과하고있는 것으로 의심됩니다. :-)
스트림이 있습니다 (이 경우 Stringio 객체이지만 일반적인 경우에도 궁금합니다).u003Clength>u003Cdata> "형식, 예를 들어 :
data = StringIO("\x07\x00\x00\x00foobar\x00\x04\x00\x00\x00baz\x00")
이제 이것을 읽을 수있는 유일한 명확한 방법은 초기화 된 루프를 사용하는 것입니다.
len_name = data.read(4)
while len_name != "":
len_name = struct.unpack("<I", len_name)[0]
names.append(data.read(len_name))
len_name = data.read(4)
C와 같은 언어로, 나는 단지 read(4)
에서 while
테스트 조항이지만 물론 파이썬에는 효과가 없습니다. 이것을 달성하는 더 좋은 방법에 대한 생각이 있습니까?
해결책
반복을 결합 할 수 있습니다 iter () 센티넬과 함께 :
for block in iter(lambda: file_obj.read(4), ""):
use(block)
다른 팁
텍스트 파일에서 줄을 반복하는 방법을 보셨습니까?
for line in file_obj:
use(line)
자신의 발전기로 똑같은 일을 할 수 있습니다.
def read_blocks(file_obj, size):
while True:
data = file_obj.read(size)
if not data:
break
yield data
for block in read_blocks(file_obj, 4):
use(block)
또한보십시오:
나는 이미 언급 된 반복 기반 솔루션을 선호하여 이것을 For-loop로 바꾸는 것을 선호합니다. 직접 작성된 또 다른 솔루션은 Knuth의 "루프 앤 반"입니다.
while 1:
len_name = data.read(4)
if not len_name:
break
names.append(data.read(len_name))
당신은 그것이 자체 발전기에 쉽게 들어오는 방법을 비교하여 for-loop로 사용하는 방법을 볼 수 있습니다.
예측 한 바와 같이, 일반적이고 가장 인기있는 답변은 매우 전문화 된 발전기를 사용하여 "한 번에 4 바이트를 읽습니다". 때때로 일반성은 어렵지 않습니다 (그리고 훨씬 더 보람있는 ;-), 그래서, 나는 대신 다음과 같은 일반적인 해결책을 제안했습니다.
import operator
def funlooper(afun, *a, **k):
wearedone = k.pop('wearedone', operator.not_)
while True:
data = afun(*a, **k)
if wearedone(data): break
yield data
이제 원하는 루프 헤더는 다음과 같습니다. for len_name in funlooper(data.read, 4):
.
편집하다: wearedone
의견이 저의 약간 덜 일반적인 이전 버전을 고발 한 이후 관용 if not data:
) 모든 것의 "숨겨진 의존성"의 경우!-)
평소 스위스 군대의 루핑 나이프, itertools
, 물론 평소와 같이 괜찮습니다.
import itertools as it
for len_name in it.takewhile(bool, it.imap(data.read, it.repeat(4))): ...
또는 상당히 동등하게 :
import itertools as it
def loop(pred, fun, *args):
return it.takewhile(pred, it.starmap(fun, it.repeat(args)))
for len_name in loop(bool, data.read, 4): ...
Python의 EOF 마커는 빈 문자열이므로 반복자에 이것을 마무리하는 기능을 작성하지 않고 얻을 수있는 최선에 가깝습니다. 나는 조금 더 피스닉 방식으로 글을 쓸 수 있습니다. while
처럼:
while len_name:
len_name = struct.unpack("<I", len_name)[0]
names.append(data.read(len_name))
len_name = data.read(4)
가독성에 대한 Tendayi의 제안 RE 기능 및 반복자와 함께 갈 것입니다.
def read4():
len_name = data.read(4)
if len_name:
len_name = struct.unpack("<I", len_name)[0]
return data.read(len_name)
else:
raise StopIteration
for d in iter(read4, ''):
names.append(d)