JDM*_*JDM 5 python utf-8 file-writing python-2.7 python-3.x
我正在开发一个 Python 3 Tkinter 应用程序(操作系统是 Windows 10),其整体功能包括以下详细信息:
读取多个可能包含 ascii、cp1252、utf-8 或任何其他编码数据的文本文件
在“预览窗口”(Tkinter 标签小部件)中显示任何这些文件的内容。
将文件内容写入单个输出文件(每次打开以追加)
对于#1:我只需通过以二进制模式打开和读取文件,即可使文件读取与编码无关。为了将数据转换为字符串,我使用一个循环,该循环遍历“可能”的编码列表,并依次尝试其中的每一个(使用error='strict'),直到遇到不引发异常的编码。这是有效的。
对于#2:一旦获得解码后的字符串,我只需调用set()Tkinter Label 的textvariable. 这也正在发挥作用。
对于#3:我以通常的方式打开一个输出文件并调用该write()方法来写入解码的字符串。当字符串被解码为 ascii 或 cp1252 时,这是有效的,但当它被解码为 utf-8 时,它会抛出异常:
'charmap' codec can't encode characters in position 0-3: character maps to <undefined>
Run Code Online (Sandbox Code Playgroud)
我四处搜索并发现了相当相似的问题,但似乎没有任何内容可以解决这个特定问题。一些进一步的复杂性限制了对我有用的解决方案:
答:我可以通过将读入数据保留为字节并以二进制形式打开/写入输出文件来回避问题,但这会导致某些输入文件内容不可读。
B. 虽然这个应用程序主要针对 Python 3,但我正在努力使其与 Python 2 交叉兼容——我们有一些缓慢/较晚的采用者将使用它。(顺便说一句,当我在 Python 2 上运行该应用程序时,它也会引发异常,但对于 cp1252 数据和 utf-8 数据都会引发异常。)
为了说明问题,我创建了这个精简的测试脚本。(我真正的应用程序是一个更大的项目,而且它也是我公司专有的 - 所以它不会公开发布!)
import tkinter as tk
import codecs
#Root window
root = tk.Tk()
#Widgets
ctrlViewFile1 = tk.StringVar()
ctrlViewFile2 = tk.StringVar()
ctrlViewFile3 = tk.StringVar()
lblViewFile1 = tk.Label(root, relief=tk.SUNKEN,
justify=tk.LEFT, anchor=tk.NW,
width=10, height=3,
textvariable=ctrlViewFile1)
lblViewFile2 = tk.Label(root, relief=tk.SUNKEN,
justify=tk.LEFT, anchor=tk.NW,
width=10, height=3,
textvariable=ctrlViewFile2)
lblViewFile3 = tk.Label(root, relief=tk.SUNKEN,
justify=tk.LEFT, anchor=tk.NW,
width=10, height=3,
textvariable=ctrlViewFile3)
#Layout
lblViewFile1.grid(row=0,column=0,padx=5,pady=5)
lblViewFile2.grid(row=1,column=0,padx=5,pady=5)
lblViewFile3.grid(row=2,column=0,padx=5,pady=5)
#Bytes read from "files" (ascii Az5, cp1252 European letters/punctuation, utf-8 Mandarin characters)
inBytes1 = b'\x41\x7a\x35'
inBytes2 = b'\xe0\xbf\xf6'
inBytes3 = b'\xef\xbb\xbf\xe6\x9c\xa8\xe5\x85\xb0\xe8\xbe\x9e'
#Decode
outString1 = codecs.decode(inBytes1,'ascii','strict')
outString2 = codecs.decode(inBytes2,'cp1252','strict')
outString3 = codecs.decode(inBytes3,'utf_8','strict')
#Assign stringvars
ctrlViewFile1.set(outString1)
ctrlViewFile2.set(outString2)
ctrlViewFile3.set(outString3)
#Write output files
try:
with open('out1.txt','w') as outFile:
outFile.write(outString1)
except Exception as e:
print(inBytes1)
print(str(e))
try:
with open('out2.txt','w') as outFile:
outFile.write(outString2)
except Exception as e:
print(inBytes2)
print(str(e))
try:
with open('out3.txt','w') as outFile:
outFile.write(outString3)
except Exception as e:
print(inBytes3)
print(str(e))
#Start GUI
tk.mainloop()
Run Code Online (Sandbox Code Playgroud)
len*_*enz 10
我知道你想要两件事:
使用open('out1.txt','w')同时违反了:
openPython 版本之间的函数有很大差异。在Python 3中,它是io.open函数,它提供了很多灵活性,例如指定文本编码。在Python 2中,返回的文件句柄处理8位字符串而不是Unicode字符串(文本)。您可以通过以下方式避免这一切io.open('out1.txt', 'w', encoding='utf8'):
utf-8-sig编解码器支持编写带有 BOM 的 UTF-8,使 Windows 应用程序能够识别以 UTF-8 编码的文件。该编解码器还会从输入流中删除UTF-8 BOM 签名(如果在用于读取时存在)。io模块已向后移植到 Python 2.7。这通常符合 Py2/3 兼容的条件,因为对 <= 2.6 版本的支持已经结束很久了。旁注:您提到了一个用于检测输入编解码器的简单启发式方法。如果确实无法获取此信息,您应该考虑使用chardet。
| 归档时间: |
|
| 查看次数: |
8297 次 |
| 最近记录: |