如何使用Unicode编码创建临时文件?

dba*_*osa 19 python unicode temporary-files

当我open()用来打开文件时,我无法编写unicode字符串.我了解到我需要使用codecs并使用Unicode编码打开文件(请参阅http://docs.python.org/howto/unicode.html#reading-and-writing-unicode-data).

现在我需要创建一些临时文件.我试图使用该tempfile库,但它没有任何编码选项.当我尝试在临时文件中写入任何unicode字符串时tempfile,它会失败:

#!/usr/bin/python2.6
# -*- coding: utf-8 -*-
import tempfile
with tempfile.TemporaryFile() as fh:
  fh.write(u"Hello World: ä")
  fh.seek(0)
  for line in fh:
    print line
Run Code Online (Sandbox Code Playgroud)

如何在Python中使用Unicode编码创建临时文件?

编辑:

  1. 我正在使用Linux,我得到的错误消息是:

    Traceback (most recent call last):
      File "tmp_file.py", line 5, in <module>
        fh.write(u"Hello World: ä")
    UnicodeEncodeError: 'ascii' codec can't encode character u'\xe4' in position 13: ordinal not in range(128)
    
    Run Code Online (Sandbox Code Playgroud)
  2. 这只是一个例子.在实践中,我试图编写一些API返回的字符串.

dfb*_*dfb 19

其他人的答案都是正确的,我只是想澄清一下发生了什么:

文字'foo'和文字之间的区别在于u'foo'前者是字节串,后者是Unicode对象.

首先,要了解Unicode是字符集.UTF-8是编码.Unicode对象是前者 - 它是一个Unicode字符串,不一定是UTF-8.在您的情况下,字符串文字的编码将是UTF-8,因为您在文件的第一行中指定了它.

要从字节字符串中获取Unicode字符串,请调用该.encode()方法:

>>>> u"????".encode("utf-8") == "????"
True
Run Code Online (Sandbox Code Playgroud)

同样,您可以在调用中调用string.encode,write并获得与删除相同的效果u.

如果您没有在顶部指定编码,例如,如果您正在从另一个文件中读取Unicode数据,则应在其到达Python字符串之前指定它所处的编码.这将决定它将如何以字节(即str类型)表示.

那么,你得到的错误只是因为tempfile模块期待一个str对象.这并不意味着它不能处理unicode,只是它希望你传入一个字节字符串而不是Unicode对象 - 因为没有你指定编码,它就不知道如何将它写入临时文件.

  • 是.因此,没有必要使用一些魔术unicode选项打开tempfile,它足以编写一个显式编码的字符串:`fh.write(u'föobār'.encode('utf-8'))`.如果您的大部分角色都是CJK,请将'utf-8'替换为'utf-16'. (3认同)
  • @9000:如果您使用“utf-16”,请注意此方法。如果这样做,您将必须一次写入整个文件,因为encode('utf-16')也会输出文件BOM。如果您有多个字符串要写入同一个文件,则第一个字符串应使用 .encode('utf-16') ,后续字符串应使用 .encode('utf-16-le') ,但不会发送 BOM。使用一些神奇的 unicode 选项可以避免这个陷阱。 (2认同)

Sep*_*rvi 9

tempfile.TemporaryFile 在Python 3中编码选项:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import tempfile
with tempfile.TemporaryFile(mode='w+', encoding='utf-8') as fh:
  fh.write("Hello World: ä")
  fh.seek(0)
  for line in fh:
    print(line)
Run Code Online (Sandbox Code Playgroud)

请注意,现在您需要指定mode ='w +'而不是默认的二进制模式.另请注意,Python 3中的字符串文字是隐式Unicode,没有u修饰符.

如果您遇到Python 2.6,临时文件总是二进制文件,您需要在将Unicode字符串写入文件之前对其进行编码:

#!/usr/bin/python
# -*- coding: utf-8 -*-
import tempfile
with tempfile.TemporaryFile() as fh:
  fh.write(u"Hello World: ä".encode('utf-8'))
  fh.seek(0)
  for line in fh:
    print line.decode('utf-8')
Run Code Online (Sandbox Code Playgroud)

Unicode指定字符集,而不是编码,因此在任何一种情况下,您都需要一种方法来指定如何编码Unicode字符!


Mat*_*Rav 7

由于我正在使用应该在Python 2和Python 3中运行的TemporaryFile对象的Python程序,我发现手动编码所有写为UTF-8的字符串并不像其他答案所建议的那样令人满意.

相反,我已经编写了以下小的polyfill(因为我找不到六个类似的东西)来将类似二进制文件的对象包装到类似UTF-8文件的对象中:

from __future__ import unicode_literals
import sys
import codecs
if sys.hexversion < 0x03000000:
    def uwriter(fp):
        return codecs.getwriter('utf-8')(fp)
else:
    def uwriter(fp):
        return fp
Run Code Online (Sandbox Code Playgroud)

它以下列方式使用:

# encoding: utf-8
from tempfile import NamedTemporaryFile
with uwriter(NamedTemporaryFile(suffix='.txt', mode='w')) as fp:
    fp.write('Hællo wörld!\n')
Run Code Online (Sandbox Code Playgroud)


dba*_*osa 6

我找到了一个解决方案:创建一个不会自动删除的临时文件tempfile,关闭它并使用codecs以下命令再次打开它:

#!/usr/bin/python2.6
# -*- coding: utf-8 -*-

import codecs
import os
import tempfile

f = tempfile.NamedTemporaryFile(delete=False)
filename = f.name
f.close()

with codecs.open(filename, 'w+b', encoding='utf-8') as fh:
  fh.write(u"Hello World: ä")
  fh.seek(0)
  for line in fh:
    print line

os.unlink(filename)
Run Code Online (Sandbox Code Playgroud)