해결 방법은 tarinfo 대신 직접 이름으로 extractfile
을 사용하는 것입니다. 이 작품 :
왜 이런 일이에 관해서는
def tariter(filename):
with tarfile.open(filename) as archive:
while True:
tarinfo = archive.next()
if tarinfo is None:
break
if tarinfo.isreg():
handle = archive.extractfile(tarinfo) # LINE CHANGED
data = handle.read()
handle.close()
yield tarinfo, data
: TarFile.next()
는 None
을 반환하는 대신 StopIteration
인상 때문에 하지 반복자 프로토콜을 구현한다.
이터레이터 프로토콜에는 반복자를 반환하는 컨테이너 요소의 "외부"부분과 반복자 자체 인 "내부"부분의 두 부분이 있습니다.
컨테이너는 을 구현해야하며, 이는 반복자 인 새 개체를 반환합니다. TarFile.__iter__()
은 새 TarIter
개체를 반환합니다.
이터레이터 자체 (TarIter
)는 __iter__()
(항상 self
을 반환) 및 next()
을 구현합니다. 또한 원래 컨테이너의 항목에 대한 자체 인덱스가 있어야합니다. 이렇게하면 별도의 반복이 서로 어지럽히 지 않고 동일한 컨테이너에서 여러 개의 다른 반복자를 생성 할 수 있습니다. 다른 사람이 그들이 엉망 반복을 것이다 TarFile
에서 제공하는 의사 반복 프로토콜을 사용 그래서 만약
TarFile.next()
그러나, 하지이 반복에 대해 별도의 인덱스를 사용한다.
이것은 여기에서 발생하는 것 같습니다. TarFile.extractfile(filename)
은 현재 TarFile
에있는 일치하는 파일이 TarFile.__iter__()
대신 사용 된 TarFile.next()
을 사용하여 찾습니다. 이렇게하면 "다음 항목"색인이 손상되어 이 으로 돌아오고 첫 번째 extractfile()
호출 이후에 반환됩니다.당신이 extractfile(tarinfo)
를 사용하는 경우
그러나 tarinfo
개체가 일치하는 파일 이름을 찾고 archive
객체를 통해 추구하지 않고 문자열 내용을 추출 할 수 TarFile
하기에 충분한 메타 데이터를 가지고있다. 따라서 archive.extractfile(tarinfo)
은 archive.extractfile(tarinfo.name)
보다 빠릅니다.
일반적으로 컬렉션 개체 (예 : TarFile
)는 이 아니고은 반복되지만 새 개체를 반복하여 생성해야합니다. TarFile.next()
의 단순한 존재는 나쁜 디자인의 냄새를 풍깁니다. 아마도 좋은 이유가 있지만, 을 사용하지 않아도됩니다!
대신이 작업을 수행 :
def tariter(filename):
with tarfile.open(filename) as archive:
# use TarIter object for iteration over archive
for tarinfo in archive:
if tarinfo.isreg():
handle = archive.extractfile(tarinfo)
data = handle.read()
handle.close()
yield tarinfo, data
이 명확하고, 내가 너무 조금 더 빨리 내기 것이다.
'archive.next'가 None을 반환합니까? 이것은 또한'tarinfo.isreg()'에서 실패 할 수 있습니다. 거짓이면'break'가 호출 될 때까지 spinloop을 입력 할 수 있습니다. – slezica
그래, 디버깅하기 위해'print' 문을 추가했습니다. 또한,'archive.next'는'None'을 리턴해야하지만, 아카이브의 끝에 도달 할 때만 ...'isreg()'는 디렉토리를 필터링하는 역할 만합니다. 내용은 내가 아는 한별로 중요하지 않아야한다. – liori
방금이 코드를 로컬에서 시도 했으므로 동일한 결과가 나타납니다. 이것은 계약 문제이며 호기심을 불러 일으켰습니다. 내가 찾을 수있는 것을 보겠습니다. – slezica