Почему я не могу дважды вызвать read() для открытого файла?

#python #file

Вопрос:

Для упражнения, которое я выполняю, я пытаюсь прочитать содержимое данного файла дважды, используя этот read() метод. Странно, но когда я вызываю его во второй раз, он, похоже, не возвращает содержимое файла в виде строки?

Вот код

 f = f.open()

# get the year
match = re.search(r'Popularity in (d )', f.read())

if match:
  print match.group(1)

# get all the names
matches = re.findall(r'<td>(d )</td><td>(w )</td><td>(w )</td>', f.read())

if matches:
  # matches is always None
 

Конечно, я знаю, что это не самый эффективный или лучший способ, дело не в этом. Вопрос в том, почему я не могу позвонить read() дважды? Нужно ли мне сбросить дескриптор файла? Или закройте / снова откройте файл, чтобы сделать это?

Комментарии:

1. Откуда у вас появилась идея, что чтение не изменит состояние файла? Какой справочник или учебник вы используете?

2. Я считаю, что закрытие и повторное открытие файла должно работать на основе приведенных ниже ответов.

3. @Shynthriir: Закрытие и повторное открытие файла не всегда является хорошей идеей, так как это может иметь другие последствия в системе (временные файлы, инкрон и т.д.).

4. Я просто хочу констатировать очевидное: Вы дважды вызывали read ()!

5. W/R/T/ S. Лотт, и начиная с 5 лет: это действительно должно быть в документации по python. Не очевидно, что следует предполагать, что чтение файлового объекта изменит состояние чего-либо, особенно если вы привыкли работать с неизменяемыми данными/программированием в функциональном стиле…

Ответ №1:

Вызов read() считывает весь файл и оставляет курсор чтения в конце файла (больше читать нечего). Если вы хотите прочитать определенное количество строк за один раз , вы можете использовать readline() readlines() или перебирать строки с for line in handle: помощью .

Чтобы ответить на ваш вопрос напрямую, как только файл был прочитан, read() вы можете использовать seek(0) для возврата курсора чтения в начало файла (документы здесь). Если вы знаете, что файл не будет слишком большим, вы также можете сохранить read() выходные данные в переменной, используя их в своих findall выражениях.

Пс. Не забудьте закрыть файл после того, как закончите с ним.

Комментарии:

1. 1, Да, пожалуйста, прочитайте во временную переменную, чтобы избежать ненужного ввода-вывода файлов. Это ложная экономия, что вы экономите какую-либо память, потому что у вас меньше (явных) переменных.

2. @NickT: Я бы ожидал, что небольшой файл, считываемый несколько раз, кэшируется ОС (по крайней мере, в Linux/OSX), поэтому для двойного чтения не требуется дополнительный ввод-вывод файлов. Большие файлы, которые не помещаются в память, не кэшируются, но вы не хотите считывать их в переменную, потому что вы начнете обмениваться. Поэтому в случае сомнений всегда читайте несколько раз. Если вы точно знаете, что файлы маленькие, делайте все, что дает самая хорошая программа.

3. Демонтаж может быть автоматизирован с with помощью .

Ответ №2:

Как предлагали другие ответы, вы должны использовать seek() .

Я просто напишу пример:

 >>> a = open('file.txt')
>>> a.read()
#output
>>> a.seek(0)
>>> a.read()
#same output
 

Ответ №3:

Все, кто до сих пор отвечал на этот вопрос, абсолютно правы — read() просматривают файл, поэтому после того, как вы его вызвали, вы не сможете позвонить ему снова.

Я добавлю, что в вашем конкретном случае вам не нужно возвращаться к началу или открывать файл заново, вы можете просто сохранить прочитанный текст в локальной переменной и использовать его дважды или столько раз, сколько захотите, в своей программе:

 f = f.open()
text = f.read() # read the file into a local variable
# get the year
match = re.search(r'Popularity in (d )', text)
if match:
  print match.group(1)
# get all the names
matches = re.findall(r'<td>(d )</td><td>(w )</td><td>(w )</td>', text)
if matches:
  # matches will now not always be None
 

Комментарии:

1. 1 На самом деле это было предлагаемое решение для этого упражнения ( code.google.com/intl/de-DE/edu/languages/google-python-class/… ). Но почему-то мне не пришло в голову хранить строку в переменной. Д’о!

2. В Python3 используйте pathlib. from pathlib import Path; text = Path(filename).read_text() Заботится об открытии, закрытии и т. Д.

Ответ №4:

Указатель чтения перемещается после последнего прочитанного байта/символа. Используйте этот seek() метод для перемотки указателя чтения к началу.

Ответ №5:

Каждый открытый файл имеет соответствующую позицию.
Когда вы читаете (), вы читаете с этой позиции. Например read(10) , считывает первые 10 байт из только что открытого файла, затем другой read(10) считывает следующие 10 байт. read() без аргументов считывает все содержимое файла, оставляя позицию файла в конце файла. В следующий раз, когда вы позвоните read() , читать будет нечего.

Вы можете использовать seek для перемещения позиции файла. Или, возможно, лучше в вашем случае было бы сделать один read() и сохранить результат для обоих поисков.

Ответ №6:

read() потребляет. Таким образом, вы можете сбросить файл или перейти к началу перед повторным чтением. Или, если это соответствует вашей задаче, вы можете использовать read(n) только n байты.

Ответ №7:

Я всегда нахожу метод чтения чем — то вроде прогулки по темному переулку. Вы спускаетесь немного вниз и останавливаетесь, но если вы не считаете свои шаги, вы не уверены, как далеко вы продвинулись. Поиск дает решение путем изменения положения, другой вариант-указать, который возвращает положение вдоль файла. Возможно,API файлов Python может объединить чтение и поиск в read_from(позиция, байты), чтобы упростить его — пока это не произойдет, вы должны прочитать эту страницу.