Python EOF для многобайтовых запросов file.read()

Документы Python на file.read() утверждают, что An empty string is returned when EOF is encountered immediately. В документации далее говорится:

Обратите внимание, что этот метод может вызвать базовый C функции fread() подробнее чем один раз, пытаясь приобрести как как можно ближе к размеру байтов. Также обратите внимание, что в режиме без блокировки, меньше данных, чем было запрошено, может быть возвращается, даже если параметр размера.

Я считаю, что Guido сделал свое мнение о том, что не добавляет f.eof() PERFECTLY CLEAR, поэтому нужно использовать способ Python!

Однако для меня не ясно, есть ли окончательный тест, который вы достигли EOF, если вы получили меньше, чем запрошенные байты от чтения, но вы получили некоторые.

т

with open(filename,'rb') as f:
    while True:
        s=f.read(size)
        l=len(s) 
        if l==0: 
            break     # it is clear that this is EOF...
        if l<size:
            break      # ? Is receiving less than the request EOF???

Является ли это потенциальной ошибкой break, если вы получили меньше байтов, запрошенных при вызове file.read(size)?

Ответ 1

Вы не думаете с вашей кожей змеи на... Python не C.

Во-первых, обзор:

  • st = f.read() читает EOF, или если он открыт как двоичный, до последнего байта;
  • st = f.read(n) пытается читать n байты и не более чем n bytes;
  • st = f.readline() читает строку за раз, строка заканчивается на "\n" или EOF;
  • st = f.readlines() использует readline() для чтения всех строк в файле и возвращает список строк.

Если метод чтения файла находится в EOF, он возвращает ''. Тот же тип теста EOF используется в других подобных файлах, таких как StringIO, socket.makefile и т.д. Возврат менее n байтов из f.read(n), безусловно, НЕ является диспозитивным тестом для EOF! код может работать 99.99% времени, это время, когда оно не работает, что было бы очень неприятно найти. Кроме того, это плохая форма Python. Единственное, что нужно для n в этом случае - установить верхний предел на размер возвращаемого значения.

Каковы некоторые из причин, по которым файлы-подобные методы Python возвращают меньше n bytes?

  • EOF, безусловно, является общей причиной;
  • Сетевой сокет может отключиться при чтении, но остается открытым;
  • Точно n байты могут привести к разрыву между логическими многобайтовыми символами (например, \r\n в текстовом режиме и, я думаю, многобайтовым символом в Юникоде) или некоторой базовой структурой данных, не известной вам;
  • Файл находится в неблокирующем режиме, и другой процесс начинает обращаться к файлу;
  • Временный не-доступ к файлу;
  • Основное условие ошибки, потенциально временное, в файле, диске, сети и т.д.
  • Программа получила сигнал, но обработчик сигнала проигнорировал его.

Я бы переписал ваш код таким образом:

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

        # process the data in s...

Или напишите генератор :

def blocks(infile, bufsize=1024):
    while True:
        try:
            data=infile.read(bufsize)
            if data:
                yield data
            else:
                break
        except IOError as (errno, strerror):
            print "I/O error({0}): {1}".format(errno, strerror)
            break

f=open('somefile','rb')

for block in blocks(f,2**16):
    # process a block that COULD be up to 65,536 bytes long

Ответ 2

Вот что говорит моя компилятор C для функции fread():

size_t fread( 
   void *buffer,
   size_t size,
   size_t count,
   FILE *stream 
);

fread возвращает количество полных элементов на самом деле читается, что может быть меньше подсчитать, произошла ли ошибка или если конец файла встречается раньше достигая счета.

Итак, похоже, что получение меньше size означает либо произошла ошибка, либо достигнута EOF - поэтому break выход из цикла будет правильным.