Який ідеальний аналог у Python для "поки не EOF"


115

Щоб прочитати якийсь текстовий файл на C або Pascal, я завжди використовую такі фрагменти, щоб прочитати дані до EOF:

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

Таким чином, мені цікаво, як я можу зробити це просто і швидко в Python?

Відповіді:


191

Проведіть петлю над файлом, щоб прочитати рядки:

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

Файлові об'єкти є ітерабельними та рядками дохідності до EOF. Використовуючи файловий об'єкт як ітерабельний, використовується буфер для забезпечення виконання читачами.

Ви можете зробити те ж саме з 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

1
Читання рядків трохи небезпечно для загальних двійкових файлів, тому що, можливо, у вас є довгий рядок
6GiB

@LtWorf: саме тому я показую, як читати бінарні файли шматками, а не рядками.
Martijn Pieters

Я читаю з stdinзапущеного процесу ... так що він ніколи не має EOF, поки я не вб'ю процес. Але потім я доходжу до "кінця до теперішнього часу" і заходжу в тупик. Як виявити це, а не тупик? Начебто, якщо немає нових рядків, перестаньте читати файли (навіть якщо немає EOF, який у моєму випадку ніколи не буде).
Чарлі Паркер

@CharlieParker: якщо ви потрапили в глухий кут, то, ймовірно , щось забуває промивати буфер. Без власне MCVE важко сказати щось більше, ніж це.
Martijn Pieters

61

Ви можете наслідувати ідіому C в Python.

Щоб прочитати буфер до 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)

Вам потрібно використовувати while True / breakконструкцію, оскільки в Python немає жодного тесту eof, крім відсутності байтів, повернутих з прочитаного.

У мові C:

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

Однак у Python цього не може бути:

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

тому що призначення не дозволяється в виразах у Python (хоча останні версії 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: Зараз це :-)
dawg

3
Як програміст на C і Perl, для мене було вирішальне твердження, що призначення не допускається у виразах .
CODE-READ

1
Метод "в той час як істинно" також корисний, коли вам потрібно працювати над декількома вхідними рядками за кожну ітерацію, що ідіоматичний Python не дозволяє (наскільки я можу сказати, все одно).
Дональд Сміт

Ви не повинні читати рядки, якщо не робите припущення щодо файлу. Двійковий файл може мати величезні рядки…
LtWorf

Здається, є перевага перед неідіоматичним readline()способом: ви можете робити дрібнозернисті поводження з помилками, як ловлі UnicodeDecodeError, чого ви не можете зробити з ідіоматичною forітерацією.
flow2k

17

Ідіома Python для відкриття файлу та читання його по черзі:

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

Файл автоматично закриється в кінці вищевказаного коду ( withконструкція про це піклується).

Нарешті, варто зазначити, що lineзбережеться нижня лінія. Це можна легко видалити за допомогою:

line = line.rstrip()

1
+1, також вказуючи ОП, що це не те саме, що дуже подібне for line in f.readlines(): ..., загальноприйняте рішення.
jedwards

12

Ви можете використовувати фрагмент коду нижче для читання рядка за рядком до кінця файлу

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

    # Do Something

    line = obj.readline()

1
ІМО, це єдина відповідь, яка найкраще відображає запитання.
gvrocha

Часто повторення між рядками може спотворювати структуру програми. Наприклад, за допомогою мовного аналізатора потрібно прочитати рядки та обробити їх послідовно. Ви не хочете реструктурувати верхній рівень просто так, щоб ви могли циклічно читати рядки, а потім відправляти їх у аналізатор.
Джонатан Старр

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), не читаючи жодних даних."
Тадг Макдональд-Дженсен

1
@ TadhgMcDonald-Jensen Ну, так, так і буде. Як дивно. Неправдиву претензію відкликано, а несправедливий позов видалено
TesselilingHeckler

1

Ви можете використовувати наступний фрагмент коду. readlines () читає одразу у всьому файлі та розбиває його на рядки.

line = obj.readlines()

0

Окрім великої відповіді @ dawg, еквівалентне рішення за допомогою оператора моржів (Python> = 3,8):

with open(filename, 'rb') as f:
    while buf := f.read(max_size):
        process(buf)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.