Python无法解析txt文件,但文件确认是'txt'文件
我有一段Python代码,可以正常读取一个txt文件。但是我的同事给了我另一组文件,看起来也是txt文件。当我用同样的Python代码运行时,每一行的读取结果都不对。
对于新文件,如果某一行是240,022414114120,-500,Bauer_HS5,0,它会被读取成str:2[]4[]0 []0[]2[]2[]4..... 这些字符之间的小方块和前面的问号都是无效字符。
然后它会进一步被转换成类似这样的内容:[['\xff\xfe2\x004\x000\x00', '\x000\x002\x002\x004\x001\x004\x001\x001\x004\x001\x002\x000\x00', '\x00-\x005\x000\x000\x00',......
不过,如果我手动创建一个正常的文本文件,并把输入文件的内容复制粘贴过去,解析器就能正确读取每一行。所以我在想,输入文件可能和正常的文本文件类型不一样,但文件的后缀确实是'txt'。
这些文件来自一个定期向我们的服务器发送文件的设备。这个解析器在另一个做同样事情的设备上工作得很好。而且两个设备的文件都是'txt'类型。
每一行是通过 {{{ for line in self._infile.xreadlines(): }}} 读取的。
我很困惑,为什么会这样。
我的Python代码如下。
def __init__(self, infile=sys.stdin, outfile=sys.stdout):
if isinstance(infile, basestring):
infile = open(infile)
if isinstance(outfile, basestring):
outfile = open(outfile, "w")
self._infile = infile
self._outfile = outfile
def sort(self):
lines = []
last_second = None
for line in self._infile.xreadlines():
line = line.replace('\r\n', '')
fields = line.split(',')
if len(fields) < 2:
continue
second = fields[1]
if last_second and second != last_second:
lines = sorted(lines, self._sort_lines)
self._outfile.write("".join([','.join(x) for x in lines]))
#self._outfile.write("\r\n")
lines = []
last_second = second
lines.append(fields)
if lines:
lines = sorted(lines, self._sort_lines)
self._outfile.write("".join([','.join(x) for x in lines]))
#self._outfile.write("\r\n")
self._infile.close()
self._outfile.close()
1 个回答
你提到的文件开头是 "\xff\xfe"
这两个字符。这两个字符组成了一个叫做“字节顺序标记”的东西,表示这个文件是用“UTF-16-LE”编码的,也就是16位的Unicode编码,低字节在前。你的Python脚本是用8位编码来读取这个文件(可能是你系统默认的编码),所以你看到很多多余的空字符(这些是16位字符的高字节)。
至于这个文件为什么会有不同的编码,我不能确定。Windows的文本编辑器(比如记事本)在你不小心的情况下,常常会默默地以不太有用的方式重新编码文件,所以可能是你的同事在编辑器中预览了这个文件,然后保存后再转发给你。
总之,最简单的解决办法可能是重新编码这个文件。有很多工具可以在不同的操作系统上做到这一点,或者你也可以自己写一个。下面是一个简单的Python函数,用来重新编码文件(希望如果编码参数不对,它能抛出异常,但也不一定总是这样):
def renecode_file(filename, from_encoding="UTF-16-LE", to_encoding="ascii"):
with open(filename, "rb") as f:
in_bytes = f.read() # read bytes
text = in_bytes.decode(from_encoding) # decode to unicode
out_bytes = text.encode(to_encoding) # reencode to new encoding
with open(filename, "wb") as f:
f.write(out_bytes) # write back to the file
如果你得到的文件总是用UTF-16编码的,你可以修改你的脚本,让它自动解码。在Python 2.7中,我建议使用 io
模块的 open
函数(这和Python 3中的常规 open
函数是一样的)。不过要注意,返回的文件对象不支持 xreadlines
方法,因为这个方法早就被弃用了(你可以直接遍历文件)。