2012-05-08 27 views
14

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

现在我需要创建一些临时文件。我试图使用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 

如何建立与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) 
    
  2. 这仅仅是一个例子。在实践中,我试图编写一些API返回的字符串。

回答

16

其他人的答案是正确的,我只是想弄清楚这是怎么回事:

字面“富”和文字u'foo”之间的区别在于,前者是字节的字符串,而后者是Unicode对象

首先,明白Unicode是字符集。 UTF-8是编码。 Unicode对象是关于前者的 - 它是一个Unicode字符串,不一定是UTF-8。在你的情况下,字符串文字的编码将是UTF-8,因为你在文件的第一行中指定了它。

要想从一个字节串Unicode字符串,调用.encode方法

>>>> u"ひらがな".encode("utf-8") == "ひらがな" 
True 

同样,你可以打电话给你的string.encode在write呼叫并达到同样的效果只是去掉u

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

然后,您所得到的错误仅仅是因为tempfile模块期望str对象。这意味着它不能处理unicode,只是它期望你传递一个字节字符串而不是一个Unicode对象 - 因为没有你指定一个编码,它不知道如何写它临时文件。

+2

是的。所以,不需要用一些神奇的unicode选项来打开tempfile,这足以编写一个明确编码的字符串:'fh。写(u'föobār'.encode('utf-8'))'。如果大多数角色都是CJK,请用'utf-16'替换'utf-8'。 – 9000

+1

@ 9000:如果您使用'utf-16',请注意此方法。如果这样做,您将不得不一次写入整个文件,因为encode('utf-16')也会输出文件BOM。如果你有几个字符串写入同一个文件,第一个应该使用.encode('utf-16'),而后面的使用.encode('utf-16-le')来发送BOM。使用一些神奇的unicode选项可以避免这个陷阱。 – kriss

+0

'“abc”'是Python 3中的一个Unicode字符串,或者存在于'from __future__ import unicode_literals'中。 – jfs

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) 
+0

我很抱歉,但这并不理想。请参阅@ spinning_plate的回答和我的评论;事情比较简单。 – 9000

+0

@ 9000我在这里看不到'spinning_plate'的答案。 – guettli

+0

@guettli:肯定是某种打字错误;我一定是指'dfb'的答案,目前已被接受。 – 9000

0

掉落你使你的代码为我工作:

fh.write("Hello World: ä") 

我想这是因为它已经是unicode。

+0

文件是否有正确的输出? – dfb

+0

是的,在没有u的情况下在Linux机器上运行脚本会产生正确的输出'Hello World:ä' – John

+0

是的,这可行... 实际上,在我的真实程序中,我从某些API获取输入,失败了,所以它不是因为我的代码中的“你”。 – dbarbosa

1

您正试图将unicode对象(u"...")写入临时文件,您应该在其中使用编码字符串("...")。您不必明确地通过"encode="参数,因为您已经在第二行("# -*- coding: utf-8 -*-")中说明了编码。只需使用fh.write("ä")而不是fh.write(u"ä"),你应该没问题。

+0

是的,这是有效的,但我实际上正在尝试编写一些API返回的字符串,所以在我的代码中没有'(u“...”)''。我用这些信息更新了我的问题。 我尝试了两个文件的例子,'fh.write(other_file.f())'工作与否取决于具有编码或不编码的其他文件。在我的真实代码中,我没有任何控制创建字符串的代码。 – dbarbosa

6

tempfile.TemporaryFile有encoding option in 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) 

注意,现在你需要指定模式= 'W +',而不是默认的二进制模式。还要注意,字符串文字在Python 3中是隐含的Unicode,没有修饰符。

如果你坚持Python 2.6, temporary files总是二进制,你需要将其写入文件之前将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') 

的Unicode指定字符集,而不是编码,因此在任你需要一种方法来指定如何编码Unicode字符!

+0

在打印之前,解码从文件中读取的8位字符串(在Python 2示例中),将其转换为Unicode字符串也是一个好主意。 (修复。) –

4

因为我正在使用Python 2和Python 3运行的TemporaryFile对象的Python程序,所以我不认为手动编码所有字符串都像其他答案建议的那样编写为UTF-8是令人满意的。

相反,我写了下面的小填充工具(因为我无法找到六个类似的东西)来包装一个二进制文件的对象为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 

它以下列方式使用:

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

设置sys作为默认编码为UTF-8将解决这一问题编码

import sys 
reload(sys) 
sys.setdefaultencoding('utf-8') #set to utf-8 by default this will solve the errors 

import tempfile 
with tempfile.TemporaryFile() as fh: 
    fh.write(u"Hello World: ä") 
    fh.seek(0) 
    for line in fh: 
    print line 
相关问题