파이썬에서“EOF는 아니지만”에 대한 완벽한 대응은 무엇입니까?


115

C 또는 Pascal에서 일부 텍스트 파일을 읽으려면 항상 다음 코드 조각을 사용하여 EOF까지 데이터를 읽습니다.

while not eof do begin
  readline(a);
  do_something;
end;

따라서 파이썬에서 어떻게 간단하고 빠르게 할 수 있을까요?

답변:


191

파일을 반복하여 행을 읽습니다.

with open('somefile') as openfileobject:
    for line in openfileobject:
        do_something()

파일 객체는 반복 가능하며 EOF까지 줄을 양보합니다. 파일 객체를 iterable로 사용하면 버퍼를 사용하여 읽기를 수행합니다.

stdin으로 똑같이 할 수 있습니다 (사용할 필요가 없습니다 raw_input():

import sys

for line in sys.stdin:
    do_something()

그림을 완성하기 위해 다음을 사용하여 이진 읽기를 수행 할 수 있습니다.

from functools import partial

with open('somefile', 'rb') as openfileobject:
    for chunk in iter(partial(openfileobject.read, 1024), b''):
        do_something()

여기서 chunk파일에서 한 번에 최대 1024 바이트를 포함하고 openfileobject.read(1024)빈 바이트 문자열을 반환하기 시작 하면 반복이 중지됩니다 .


4
참고 :의 line끝에 줄 바꿈 문자가 있습니다.
ben_joseph jul.

1
줄을 읽는 것은 일반 바이너리 파일에 대해 약간 위험합니다. 아마도 6GiB의 긴 줄이 있기 때문입니다…
LtWorf

@LtWorf : 이진 파일 줄이 아닌 청크 로 읽는 방법을 보여주는 이유 입니다.
Martijn Pieters

나는 stdin실행중인 프로세스에서 읽고 있으므로 프로세스를 죽일 때까지 EOF가 없습니다. 그러나 나는 "지금까지의 끝"에 도달하고 나는 교착 상태에 빠진다. 교착 상태가 아닌 이것을 어떻게 감지합니까? 새 줄이없는 것처럼 파일 읽기를 중지합니다 (내 경우에는 존재하지 않는 EOF가 없더라도).
Charlie Parker

@CharlieParker : 교착 상태에 도달 하면 버퍼를 플러시하는 것을 잊은 것일 수 있습니다. 실제 MCVE가 없으면 그 이상을 말하기가 어렵습니다.
Martijn Pieters

61

Python에서 C 관용구를 모방 할 수 있습니다.

버퍼를 최대 max_size바이트 수 까지 읽으려면 다음을 수행하십시오.

with open(filename, 'rb') as f:
    while True:
        buf = f.read(max_size)
        if not buf:
            break
        process(buf)

또는 텍스트 파일을 한 줄씩 :

# warning -- not idiomatic Python! See below...
with open(filename, 'rb') as f:
    while True:
        line = f.readline()
        if not line:
            break
        process(line)

읽기에서 반환 된 바이트의 부족 외에 파이썬 에는 eof 테스트while True / break없기 때문에 구문 을 사용해야 합니다.

C에서는 다음이있을 수 있습니다.

while ((ch != '\n') && (ch != EOF)) {
   // read the next ch and add to a buffer
   // ..
}

그러나 파이썬에서는 이것을 가질 수 없습니다.

 while (line = f.readline()):
     # syntax error

Python의 표현식 에서는 할당이 허용되지 않기 때문입니다 (최신 버전의 Python은 할당 표현식을 사용하여이를 모방 할 수 있지만 아래 참조).

파이썬에서 이것을하는 것은 확실히 관용적입니다 :

# THIS IS IDIOMATIC Python. Do this:
with open('somefile') as f:
    for line in f:
        process(line)

업데이트 : Python 3.8부터 할당 표현식을 사용할 수도 있습니다 .

 while line := f.readline():
     process(line)

@MartijnPieters : 지금은 :-) 않습니다
임마

3
C 및 Perl 프로그래머 로서 표현식에서 할당이 허용되지 않는다는 점은 저에게 중요했습니다.
CODE-REaD

1
"while True :"메서드는 반복 당 하나 이상의 입력 라인에서 작업해야 할 때도 유용합니다. 관용적 인 파이썬이 허용하지 않는 것입니다 (어쨌든 내가 말할 수있는 한).
도널드 스미스

파일에 대해 가정하지 않으면 행을 읽지 않아야합니다. 이진 파일은 ... 거대한 라인이있을 수 있습니다
LtWorf

비 관용적 인 readline()방법 에는 이점이있는 것 같습니다 . UnicodeDecodeError관용적 인 for반복 으로는 할 수없는 catching과 같은 세분화 된 오류 처리를 수행 할 수 있습니다 .
flow2k

17

파일을 열고 한 줄씩 읽는 Python 관용구는 다음과 같습니다.

with open('filename') as f:
    for line in f:
        do_something(line)

파일은 위 코드의 끝에서 자동으로 닫힙니다 ( with구성이 처리합니다).

마지막으로 line후행 개행을 보존 한다는 점 은 주목할 가치가 있습니다. 다음을 사용하여 쉽게 제거 할 수 있습니다.

line = line.rstrip()

1
+1, 또한 이것이 일반적으로 제안되는 솔루션 과 매우 유사 하지 않다는 OP를 지적 for line in f.readlines(): ...합니다.
jedwards 2013 년

12

아래 코드 스 니펫을 사용하여 파일 끝까지 한 줄씩 읽을 수 있습니다.

line = obj.readline()
while(line != ''):

    # Do Something

    line = obj.readline()

1
IMO, 이것은 요청 된 것을 가장 잘 반영하는 하나의 답변입니다.
gvrocha

종종 행을 반복하면 프로그램의 구조가 왜곡됩니다. 예를 들어 언어 파서에서 줄을 읽고 순서대로 처리하려고합니다. 읽기 행을 반복하여 파서로 보낼 수 있도록 최상위 수준을 재구성하고 싶지는 않습니다.
Jonathan Starr

11

위의 "파이썬 방식으로하기"에 대한 제안이 있지만 실제로 EOF를 기반으로하는 논리를 갖고 싶다면 예외 처리를 사용하는 것이 그 방법이라고 생각합니다.

try:
    line = raw_input()
    ... whatever needs to be done incase of no EOF ...
except EOFError:
    ... whatever needs to be done incase of EOF ...

예:

$ echo test | python -c "while True: print raw_input()"
test
Traceback (most recent call last):
  File "<string>", line 1, in <module> 
EOFError: EOF when reading a line

또는 프롬프트 Ctrl-Z에서 누르십시오 raw_input()(Windows, Ctrl-ZLinux).


@TessellatingHeckler 는 문서에 나와 있는 내용이 아닙니다 . "내장 함수 (input () 또는 raw_input ()) 중 하나가 데이터를 읽지 않고 EOF (파일 끝 조건)에 도달하면 발생합니다."
Tadhg McDonald-Jensen 2016

1
@ TadhgMcDonald-Jensen 음 헤이, 그렇게 될 것입니다. 얼마나 이상해. 허위 주장이 철회되고 불공정 한 반대 투표가 제거되었습니다.
TessellatingHeckler

1

다음 코드 스 니펫을 사용할 수 있습니다. readlines ()는 전체 파일을 한 번에 읽고 한 줄씩 분할합니다.

line = obj.readlines()

0

@dawg의 훌륭한 답변 외에도 해마 연산자를 사용하는 동등한 솔루션 (Python> = 3.8) :

with open(filename, 'rb') as f:
    while buf := f.read(max_size):
        process(buf)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.