【问题标题】:Fastest way to convert file from latin1 to utf-8 in python在 python 中将文件从 latin1 转换为 utf-8 的最快方法
【发布时间】:2011-01-25 04:19:28
【问题描述】:

我需要在 python 中将文件从 latin1 转换为 utf-8 的最快方法。文件很大~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()

但它仍然很慢。转换需要整个迁移时间的四分之一。

如果它比原生 python 代码更快,我也可以使用 linux 命令行实用程序。

【问题讨论】:

    标签: python


    【解决方案1】:

    您可以使用大于一行的块,并进行二进制 I/O —— 每个可能会加快速度(尽管在 Linux 上二进制 I/O 不会,因为它与文本 I/O 相同):

     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-style 编码-解码中隐含的逐字节解析应该是减慢您速度的部分原因。这种方法也是可移植的(就像你的那样),因为像\n 这样的控制字符无论如何都不需要在这些编解码器之间进行转换(在任何操作系统中)。

    这仅适用于没有多字节字符的输入编解码器,但 `latin1' 是其中之一(输出编解码器是否具有此类字符并不重要)。

    根据您的磁盘、文件系统和可用 RAM,尝试不同的块大小以找到性能最佳点。

    编辑:根据@John 的评论更改代码,并根据@gnibbler 的说明澄清条件。

    【讨论】:

    • 这仅在这种情况下是安全的,因为latin1 没有多字节字符。
    • @John,对——编辑修复。 @gnibbler,对——编辑指出这一点。
    • 为避免在解释“多字节”时出现任何歧义引起的任何疑问:它适用于每个代码点具有 固定 字节数的任何输入编码——因此是 UTF -32 是可以的,而 UTF-16 是可以的,当且仅当字符被限制为 BMP 时(如果你的缓冲区以高代理结束,splat)。
    • 这是最快的解决方案。我对所有可能的解决方案进行了测试,结果如下 1. 使用带有循环 0:03:14.343220 的编解码器 2. 使用没有循环 0:02:34.730663 的编解码器 3. 使用带有循环 0:01:21.517520 的本机 4. 使用本机无循环 0:00:18.262899 5. 使用 iconv 0:00:26.274130 6. stackoveflow 解决方案 0:00:08.001735 测试是在 1.4G 文本文件上完成的。 2 号测试是最差的。它使我的 i7 12G 机器几乎停止运行(使用了大量内存)。测试号 4 非常快,但也使用了很多内存。 Iconv 单独运行时更快,而不是从 python 运行。
    • native 表示最简单的方法,无需任何导入。 outfile.write(infile.read().decode('latin1').encode('utf-8'))
    【解决方案2】:

    如果您迫切希望使用 Python(或任何其他语言)来执行此操作,请至少以比行更大的块执行 I/O,并避免编解码器开销。

    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 输入,我会感到惊讶 :-)

    【讨论】:

      【解决方案3】:

      我会选择iconv 和系统调用。

      【讨论】:

      • Iconv for windows 被窃听:utf8 被翻译为 little endian utf16 :(
      猜你喜欢
      • 2011-09-26
      • 2011-09-05
      • 2017-02-13
      • 1970-01-01
      • 2014-03-08
      • 1970-01-01
      • 2013-09-18
      • 2018-12-26
      相关资源
      最近更新 更多