【问题标题】:Python failed to parse txt file but the file is confirmed to be 'txt' filePython 无法解析 txt 文件,但该文件被确认为 'txt' 文件
【发布时间】:2014-03-03 00:25:14
【问题描述】:

我有一段 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()

【问题讨论】:

  • 这是一个编码问题。可能是 UTF-8
  • 这个编码问题发生在哪里?这些文件来自定期向我们的服务器发送文件的设备。这个解析器适用于另一个做同样事情的设备。两个设备上的文件都是'txt'类型。
  • “txt”只是文件名的一部分。对python没关系。您能否提供失败文件中的示例行?此外,您示例中的大多数行似乎实际上与问题无关。如果您将示例缩减到最低限度,则更容易提供帮助。
  • 其中一个例子是这样的:240,022414114120,-500,Bauer_HS5,0。那么python读取的时候就变成了??2[]4[]0 []0[]2[]2[]4.....每个字符和前导问号字符之间的那些小矩形都是无效的人物。我觉得不是内容。因为如果我将新文件中的内容复制粘贴到手动创建的 txt 文件中,python 会正确读取它。
  • Bitrot 理论上是不可能的,但是文件确实损坏了,你能把文件再发给你吗?

标签: python file python-2.7 file-io


【解决方案1】:

您描述为来自您的同事的文件的开头是"\xff\xfe"。这两个字符组成了一个“字节顺序标记”,表明该文件使用“UTF-16-LE”编码(即低字节在前的 16 位 Unicode)进行编码。您的 Python 脚本使用 8 位编码读取(可能是您系统的默认编码),因此您会看到大量额外的空字符(16 位字符的高字节)。

我无法说明文件是如何获得不同编码的。 Windows 文本编辑器(如 notepad.exe)在某种程度上臭名昭著,如果您不小心对文件进行无用的静默重新编码,则可能是您的同事在编辑器中预览了文件,然后在将其转发到之前将其保存。你。

无论如何,最简单的解决方法可能是重新编码文件。有various utilities to do this on various OSs,或者您可以轻松编写自己的代码。这是一个在 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 函数(它与常规 open 在 Python 3 中使用的代码相同)。但是请注意,返回的文件对象不支持已被弃用很长时间的xreadlines 方法(直接迭代文件即可)。

【讨论】:

  • 谢谢。我认为这正是发生的事情。我相信这些文件将始终以 UTF-16 编码。解决这个问题的优雅方法是什么?在文件启动时将文件解码为 UTF-8?
猜你喜欢
  • 1970-01-01
  • 2016-04-07
  • 1970-01-01
  • 1970-01-01
  • 2016-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多