Python не читает весь текстовый файл

Я столкнулся с проблемой, с которой я не видел никого в StackOverflow или даже в Google в этом отношении.

Моя основная цель - иметь возможность заменить вхождения строки в файле другой строкой. Есть ли способ получить доступ ко всем строкам в файле.

Проблема в том, что когда я пытаюсь прочитать большой текстовый файл (1-2 ГБ) текста, python читает только его часть.

Например, я сделаю очень простую команду, например:

newfile = open("newfile.txt","w")
f = open("filename.txt","r")
for line in f:
    replaced = line.replace("string1", "string2")
    newfile.write(replaced)

И записывает только первые 382 мб исходного файла. Кто-нибудь сталкивался с этой проблемой ранее?

Я пробовал несколько разных решений, таких как использование:

import fileinput
for i, line in enumerate(fileinput.input("filename.txt", inplace=1)
   sys.stdout.write(line.replace("string1", "string2")

Но эффект тот же. Также не читается файл по частям, например, с использованием

f.read(10000)

Я сузил его до вероятной проблемы с чтением, а не с записью, потому что это происходит из-за простой распечатки строк. Я знаю, что есть еще строки. Когда я открываю его в полнотекстовом редакторе, таком как Vim, я вижу, какой должна быть последняя строка, и это не последняя строка, которую печатает python.

Может ли кто-нибудь дать какие-либо советы или что-то попробовать?

В настоящее время я использую 32-разрядную версию Windows XP с 3,25 ГБ оперативной памяти и использую Python 2.7.

*Редактировать найденное решение (спасибо Lattyware). Использование итератора

def read_in_chunks(file, chunk_size=1000): 
   while True: 
      data = file.read(chunk_size) 
      if not data: break 
      yield data

person user1297872    schedule 28.03.2012    source источник
comment
Чтение строки за строкой с помощью итератора должно быть ленивой операцией, поэтому оно должно работать независимо от размера файла. Хотя это не должно повлиять на вашу ситуацию, вы также захотите использовать with при открытии файлов - это хорошая практика, чем правильно обрабатывать закрытие в исключениях.   -  person Gareth Latty    schedule 28.03.2012
comment
Это сработало отлично! Огромное спасибо. * редактировать: я пытался опубликовать здесь код итератора, но он не форматировался, поэтому я добавил его в исходное сообщение.   -  person user1297872    schedule 28.03.2012
comment
Вы пробовали это с другим большим текстовым файлом? Есть ли что-то странное с файлом 382mb in - какой-то странный символ, который трактуется как конец файла?   -  person neil    schedule 28.03.2012
comment
У меня есть. Сначала я подумал, что это мог быть файл, но я попробовал его с файлами разного размера из разных источников. Большой, который я пробовал, был 2,6 ГБ, а самый маленький, который я пробовал, был 560 МБ, но все они останавливаются на 382 МБ.   -  person user1297872    schedule 28.03.2012
comment
Нет никаких причин, по которым ваш исходный код не должен был работать. Это также лениво, как называет это @Latty. Вам не нужно писать свой собственный итератор или читать кусками.   -  person alexis    schedule 28.03.2012
comment
Связанный вопрос: Чтение строки блокируется на 0x1A   -  person Janne Karila    schedule 28.03.2012
comment
Я хотел бы отметить, что когда я сказал итератор, я имел в виду не это - я имел в виду один, как в вашем исходном примере (for line in f). Так что, я думаю, нет проблем, но я думаю, что правильный ответ здесь - кодейп.   -  person Gareth Latty    schedule 28.03.2012


Ответы (3)


Пытаться:

f = open("filename.txt", "rb")

В Windows rb означает открытый файл в двоичном режиме. Согласно документам, текстовый режим по сравнению с двоичным режимом влияет только на символы конца строки. Но (если я правильно помню), я считаю, что открытие файлов в текстовом режиме в Windows также что-то делает с EOF (шестнадцатеричный 1A).

Вы также можете указать режим при использовании fileinput:

fileinput.input("filename.txt", inplace=1, mode="rb")
person codeape    schedule 28.03.2012
comment
Это тоже работает! Мне это решение нравится больше всего, потому что легко изменить существующий код. - person user1297872; 28.03.2012
comment
Как там то и работает? Это явно ваша проблема. Какой другой подход также сработал? Ах, я вижу в комментариях указание длины байта для чтения вместо использования readline - person jsbueno; 28.03.2012
comment
Я столкнулся с точно такой же проблемой. Он работает отлично! - person Tao Chen; 03.12.2015

Вы уверены, что проблема именно в чтении, а не в записи? Вы закрываете файл, в который записывается, либо явно newfile.close(), либо с помощью конструкции with?

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

person benroth    schedule 28.03.2012

Если вы используете файл следующим образом:

with open("filename.txt") as f:
    for line in f:
        newfile.write(line.replace("string1", "string2"))

Он должен считывать в память только одну строку за раз, если вы не храните ссылку на эту строку в памяти.
После того, как каждая строка будет прочитана, сборщик мусора python должен будет избавиться от нее. Попробуйте это и посмотрите, работает ли это для вас :)

person Serdalis    schedule 28.03.2012