Может искать и рассказывать работу с документами в кодировке UTF-8 в Python? - PullRequest
6 голосов
/ 02 октября 2009

У меня есть приложение, которое генерирует несколько больших файлов журнала> 500 МБ.

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

Таким образом, я хочу отсканировать документ один раз, создать индекс, а затем только загрузить часть документа в память, которую я хочу просмотреть за один раз.

Это работает для меня, когда я открываю «файл», читая его по одной строке за раз и сохраняя смещение с помощью file.tell (). Затем я могу вернуться к этому разделу файла позже с помощью file.seek (offset, 0).

Однако у меня проблема в том, что в файлах журнала может быть UTF-8, поэтому мне нужно открыть их с помощью модуля кодеков (codecs.open(<filename>, 'r', 'utf-8')). С полученным объектом я могу позвонить и найти, но они не совпадают.

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

Есть ли способ обойти это?

Ответы [ 4 ]

2 голосов
/ 02 октября 2009

Если true, это звучит как ошибка или ограничение модуля кодеков, так как это, вероятно, сбивает смещение байтов и символов.

Я бы использовал обычную функцию open() для открытия файла, тогда seek() / tell() даст вам смещения байтов, которые всегда согласованы. Всякий раз, когда вы хотите прочитать, используйте f.readline().decode('utf-8').

Однако следует помнить, что использование функции f.read() может оказаться в середине многобайтового символа, что приведет к ошибке декодирования UTF-8. readline() всегда будет работать.

Это не обеспечивает прозрачной обработки метки порядка байтов для вас, но, скорее всего, ваши файлы журналов в любом случае не имеют спецификаций.

1 голос
/ 02 октября 2009

Многое из того, что происходит с UTF8 в python, имеет смысл, если вы посмотрите, как это было сделано в Python 3. В вашем случае это будет иметь гораздо больше смысла, если вы прочитаете главу Файлы в Dive into Python 3. : http://diveintopython3.org/files.html

Суть в том, что file.seek и file.tell работают с позициями байтов, тогда как символы Юникода могут занимать несколько байтов. Таким образом, если вы делаете:

f.seek(10)
f.read(1)
f.tell()

Вы можете легко получить что-то отличное от 17, в зависимости от длины прочитанного вами символа.

1 голос
/ 02 октября 2009

Для UTF-8 вам на самом деле не нужно открывать файл с codecs.open. Вместо этого сначала можно прочитать файл в виде байтовой строки и только потом декодировать отдельный раздел (вызывая метод .decode для строки). Разрыв файла на границах строк безопасен; единственный небезопасный способ разбить его - это посередине многобайтового символа (который вы можете узнать по значению его байта> 128).

0 голосов
/ 02 октября 2009

Обновление: Вы не можете выполнять поиск / указание для объекта, возвращенного codec.open (). Вам нужно использовать обычный файл и декодировать строки в юникод после чтения.

Я не знаю, почему это не работает, но я не могу заставить это работать. Например, поиск работает только один раз. Затем вам нужно закрыть и снова открыть файл, что, конечно, бесполезно.

Tell не использует позиции символов, но не показывает, где находится ваша позиция в потоке (но, вероятно, там, где базовый файловый объект находится при чтении с диска).

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

...