파이썬에서“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.