Python无法解析txt文件,但文件确认是'txt'文件

0 投票
1 回答
995 浏览
提问于 2025-04-17 20:33

我有一段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 个回答

4

你提到的文件开头是 "\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 方法,因为这个方法早就被弃用了(你可以直接遍历文件)。

撰写回答