Самый быстрый способ конвертировать файл из latin1 в utf-8 в Python - PullRequest
5 голосов
/ 09 марта 2010

Мне нужен самый быстрый способ конвертировать файлы из latin1 в utf-8 в Python. Файлы большие ~ 2G. (Я перемещаю данные БД). Пока у меня есть

import codecs
infile = codecs.open(tmpfile, 'r', encoding='latin1')
outfile = codecs.open(tmpfile1, 'w', encoding='utf-8')
for line in infile:
     outfile.write(line)
infile.close()
outfile.close()

но все еще медленно. Преобразование занимает четверть всего времени миграции.

Я также мог бы использовать утилиту командной строки linux, если она работает быстрее, чем собственный код Python.

Ответы [ 3 ]

6 голосов
/ 09 марта 2010

Я бы пошел с iconv и системным вызовом.

4 голосов
/ 09 марта 2010

Вы можете использовать блоки размером более одной строки и выполнять двоичный ввод-вывод - каждый может немного увеличить скорость (хотя в Linux двоичный ввод-вывод не будет, поскольку он идентичен текстовому вводу-выводу):

 BLOCKSIZE = 1024*1024
 with open(tmpfile, 'rb') as inf:
   with open(tmpfile, 'wb') as ouf:
     while True:
       data = inf.read(BLOCKSIZE)
       if not data: break
       converted = data.decode('latin1').encode('utf-8')
       ouf.write(converted)

Побайтовый анализ, подразумеваемый при построчном чтении, преобразовании конца строки (не в Linux ;-) и кодировании-декодировании в стиле codecs.open, должен быть частью того, что замедляет вас. Этот подход также переносим (как у вас), поскольку управляющие символы, такие как \n, в любом случае не нуждаются в переводе между этими кодеками (в любой ОС).

Это работает только для входных кодеков, которые не имеют многобайтовых символов, но `latin1 'является одним из них (не имеет значения, имеют ли выходные кодеки такие символы или нет).

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

Редактировать : изменен код для @ комментария Джона и уточнены условия в соответствии с @ gnibbler.

2 голосов
/ 09 марта 2010

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

infile = open(tmpfile, 'rb')
outfile = open(tmpfile1, 'wb')
BLOCKSIZE = 65536 # experiment with size
while True:
    block = infile.read(BLOCKSIZE)
    if not block: break
    outfile.write(block.decode('latin1').encode('utf8'))
infile.close()
outfile.close()

В противном случае, используйте iconv ... Я не заглядываю под капот, но если нет специального ввода latin1, я бы удивился: -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...