【问题标题】:How to convert a file to utf-8 in Python?如何在 Python 中将文件转换为 utf-8?
【发布时间】:2010-09-16 12:32:19
【问题描述】:

我需要在 Python 中将一堆文件转换为 utf-8,而“转换文件”部分遇到了麻烦。

我想做相当于:

iconv -t utf-8 $file > converted/$file # this is shell code

谢谢!

【问题讨论】:

    标签: python encoding file utf-8


    【解决方案1】:

    你可以使用codecs module,像这样:

    import codecs
    BLOCKSIZE = 1048576 # or some other, desired size in bytes
    with codecs.open(sourceFileName, "r", "your-source-encoding") as sourceFile:
        with codecs.open(targetFileName, "w", "utf-8") as targetFile:
            while True:
                contents = sourceFile.read(BLOCKSIZE)
                if not contents:
                    break
                targetFile.write(contents)
    

    EDIT:添加BLOCKSIZE参数来控制文件块大小。

    【讨论】:

    • read() 将始终读取整个文件 - 您可能需要 .read(BLOCKSIZE),其中 BLOCKSIZE 是一次读取/写入的合适数量。
    • 在 Python 3 中:考虑使用open 而不是codecs.open(参见here
    【解决方案2】:

    这在一个小测试中对我有用:

    sourceEncoding = "iso-8859-1"
    targetEncoding = "utf-8"
    source = open("source")
    target = open("target", "w")
    
    target.write(unicode(source.read(), sourceEncoding).encode(targetEncoding))
    

    【讨论】:

    • 最好是指定二进制模式。
    • @Arafangion 为什么二进制模式会更好?谢谢!
    • @Honghe.Wu:在 Windows 上,文本模式是默认设置,这意味着您的行尾将被操作系统破坏,如果您不确定在磁盘上编码。
    • @Arafangion 如果我想指定二进制模式,该示例会是什么样子? target = open("target", "wb")还有什么变化吗?
    【解决方案3】:

    感谢回复,成功了!

    而且由于源文件是混合格式,我添加了一个要按顺序尝试的源格式列表 (sourceFormats),然后在 UnicodeDecodeError 上尝试下一种格式:

    from __future__ import with_statement
    
    import os
    import sys
    import codecs
    from chardet.universaldetector import UniversalDetector
    
    targetFormat = 'utf-8'
    outputDir = 'converted'
    detector = UniversalDetector()
    
    def get_encoding_type(current_file):
        detector.reset()
        for line in file(current_file):
            detector.feed(line)
            if detector.done: break
        detector.close()
        return detector.result['encoding']
    
    def convertFileBestGuess(filename):
       sourceFormats = ['ascii', 'iso-8859-1']
       for format in sourceFormats:
         try:
            with codecs.open(fileName, 'rU', format) as sourceFile:
                writeConversion(sourceFile)
                print('Done.')
                return
          except UnicodeDecodeError:
            pass
    
    def convertFileWithDetection(fileName):
        print("Converting '" + fileName + "'...")
        format=get_encoding_type(fileName)
        try:
            with codecs.open(fileName, 'rU', format) as sourceFile:
                writeConversion(sourceFile)
                print('Done.')
                return
        except UnicodeDecodeError:
            pass
    
        print("Error: failed to convert '" + fileName + "'.")
    
    
    def writeConversion(file):
        with codecs.open(outputDir + '/' + fileName, 'w', targetFormat) as targetFile:
            for line in file:
                targetFile.write(line)
    
    # Off topic: get the file list and call convertFile on each file
    # ...
    

    (Rudro Badhon 编辑:这结合了原始尝试多种格式,直到您没有遇到异常以及使用 chardet.universaldetector 的替代方法)

    【讨论】:

    • 对于棘手的情况,您可以尝试使用 feedparser.org 的 chardet 模块检测编码,但在您的情况下,这有点过头了。
    • 我的 Python 3.5 无法识别函数 file。这是哪里来的?
    • 是的,这个答案是 8 年前发布的,所以它是一段旧的 Python 2 代码。
    【解决方案4】:

    未知源编码类型的答案

    基于@Sébastien RoccaSerra

    python3.6

    import os    
    from chardet import detect
    
    # get file encoding type
    def get_encoding_type(file):
        with open(file, 'rb') as f:
            rawdata = f.read()
        return detect(rawdata)['encoding']
    
    from_codec = get_encoding_type(srcfile)
    
    # add try: except block for reliability
    try: 
        with open(srcfile, 'r', encoding=from_codec) as f, open(trgfile, 'w', encoding='utf-8') as e:
            text = f.read() # for small files, for big use chunks
            e.write(text)
    
        os.remove(srcfile) # remove old encoding file
        os.rename(trgfile, srcfile) # rename new encoding
    except UnicodeDecodeError:
        print('Decode Error')
    except UnicodeEncodeError:
        print('Encode Error')
    

    【讨论】:

      【解决方案5】:

      这是一个 Python3 函数,用于将任何文本文件转换为 UTF-8 编码的文件。 (不使用不必要的包)

      def correctSubtitleEncoding(filename, newFilename, encoding_from, encoding_to='UTF-8'):
          with open(filename, 'r', encoding=encoding_from) as fr:
              with open(newFilename, 'w', encoding=encoding_to) as fw:
                  for line in fr:
                      fw.write(line[:-1]+'\r\n')
      

      您可以轻松地在循环中使用它来转换文件列表。

      【讨论】:

      • 这非常适合从 is0-8859-1 转换为 utf-8!
      【解决方案6】:

      要猜测源编码是什么,您可以使用file *nix 命令。

      例子:

      $ file --mime jumper.xml
      
      jumper.xml: application/xml; charset=utf-8
      

      【讨论】:

      • 它没有回答问题。
      【解决方案7】:

      你可以使用这个one liner(假设你想从utf16转换成utf8

          python -c "from pathlib import Path; path = Path('yourfile.txt') ; path.write_text(path.read_text(encoding='utf16'), encoding='utf8')"
      

      yourfile.txt 是您的 $file 的路径。

      为此,您需要 python 3.4 或更新版本(现在可能需要)。

      下面是上面代码的一个更易读的版本

      from pathlib import Path
      path = Path("yourfile.txt")
      path.write_text(path.read_text(encoding="utf16"), encoding="utf8")
      

      【讨论】:

      • 根据您的操作系统,这可能会更改换行符控制字符。不过答案很好,谢谢。它需要更多的赞成票。就这么简单,无需关心根据 Path.write_text 的文档管理资源:Open the file in text mode, write to it, and close the file.
      【解决方案8】:

      这是我的蛮力方法。它还处理输入中混合的 \n 和 \r\n。

          # open the CSV file
          inputfile = open(filelocation, 'rb')
          outputfile = open(outputfilelocation, 'w', encoding='utf-8')
          for line in inputfile:
              if line[-2:] == b'\r\n' or line[-2:] == b'\n\r':
                  output = line[:-2].decode('utf-8', 'replace') + '\n'
              elif line[-1:] == b'\r' or line[-1:] == b'\n':
                  output = line[:-1].decode('utf-8', 'replace') + '\n'
              else:
                  output = line.decode('utf-8', 'replace') + '\n'
              outputfile.write(output)
          outputfile.close()
      except BaseException as error:
          cfg.log(self.outf, "Error(18): opening CSV-file " + filelocation + " failed: " + str(error))
          self.loadedwitherrors = 1
          return ([])
      try:
          # open the CSV-file of this source table
          csvreader = csv.reader(open(outputfilelocation, "rU"), delimiter=delimitervalue, quoting=quotevalue, dialect=csv.excel_tab)
      except BaseException as error:
          cfg.log(self.outf, "Error(19): reading CSV-file " + filelocation + " failed: " + str(error))
      

      【讨论】:

        【解决方案9】:

        将目录中的所有文件转换为 utf-8 编码。它是递归的,可以按后缀过滤文件。谢谢@Sole Sensei

        # pip install -i https://pypi.tuna.tsinghua.edu.cn/simple chardet
        import os
        import re
        from chardet import detect
        
        
        def get_file_list(d):
            result = []
            for root, dirs, files in os.walk(d):
                dirs[:] = [d for d in dirs if d not in ['venv', 'cmake-build-debug']]
                for filename in files:
                    # your filter
                    if re.search(r'(\.c|\.cpp|\.h|\.txt)$', filename):
                        result.append(os.path.join(root, filename))
            return result
        
        
        # get file encoding type
        def get_encoding_type(file):
            with open(file, 'rb') as f:
                raw_data = f.read()
            return detect(raw_data)['encoding']
        
        
        if __name__ == "__main__":
            file_list = get_file_list('.')
            for src_file in file_list:
                print(src_file)
                trg_file = src_file + '.swp'
                from_codec = get_encoding_type(src_file)
                try:
                    with open(src_file, 'r', encoding=from_codec) as f, open(trg_file, 'w', encoding='utf-8') as e:
                        text = f.read()
                        e.write(text)
                    os.remove(src_file)
                    os.rename(trg_file, src_file)
                except UnicodeDecodeError:
                    print('Decode Error')
                except UnicodeEncodeError:
                    print('Encode Error')
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-04-01
          • 1970-01-01
          • 2022-01-10
          • 2017-12-08
          • 2015-11-30
          • 2023-03-16
          • 2021-07-08
          • 2015-04-07
          相关资源
          最近更新 更多