fileinput.hook_compressed有时给我字符串,有时给我字节

2024-09-28 21:58:25 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试从许多文件中读取行。有些是gzip文件,有些是纯文本文件。在Python2.7中,我一直在使用以下代码,并且效果良好:

for line in fileinput.input(filenames, openhook=fileinput.hook_compressed):
    match = REGEX.match(line)
    if (match):
        # do things with line...

现在我转到Python3.8,它仍然可以处理纯文本文件,但是当它遇到Gzip文件时,我得到以下错误:

TypeError: cannot use a string pattern on a bytes-like object

解决这个问题的最好方法是什么?我知道我可以检查line是否是字节对象,并将其解码为字符串,但如果可能,我宁愿使用一些标志来自动将行作为字符串进行迭代;而且,我更愿意编写同时适用于Python2和Python3的代码


Tags: 文件字符串代码inforinputmatchline
1条回答
网友
1楼 · 发布于 2024-09-28 21:58:25

^{}根据它是否获得gzip文件,做了根本不同的事情。对于文本文件,它使用常规的^{}打开,默认情况下,它有效地以文本模式打开。对于^{},默认模式是二进制,这对于未知内容的压缩文件是合理的

只有二进制的限制是由^{}人为施加的。从^{}方法的代码中:

  # restrict mode argument to reading modes
   if mode not in ('r', 'rU', 'U', 'rb'):
       raise ValueError("FileInput opening mode must be one of "
                        "'r', 'rU', 'U' and 'rb'")
   if 'U' in mode:
       import warnings
       warnings.warn("'U' mode is deprecated",
                     DeprecationWarning, 2)
   self._mode = mode

这为您提供了两种解决方法

选项1

__init__之后设置_mode属性。为了避免在使用中添加额外的代码行,您可以将fileinput.FileInput子类化并直接使用该类:

class TextFileInput(fileinput.FileInput):
    def __init__(*args, **kwargs):
        if 'mode' in kwargs and 't' in kwargs['mode']:
            mode = kwargs.pop['mode']
        else:
            mode = ''
        super().__init__(*args, **kwargs)
        if mode:
            self._mode = mode

for line in TextFileInput(filenames, openhook=fileinput.hook_compressed, mode='rt'):
    ...

选项2

混用未记录的前导下划线是非常有技巧的,因此,您可以为zip文件创建一个自定义钩子。这实际上相当简单,因为您可以使用^{}的代码作为模板:

def my_hook_compressed(filename, mode):
    if 'b' not in mode:
        mode += 't'
    ext = os.path.splitext(filename)[1]
    if ext == '.gz':
        import gzip
        return gzip.open(filename, mode)
    elif ext == '.bz2':
        import bz2
        return bz2.open(filename, mode)
    else:
        return open(filename, mode)

选项3

最后,您始终可以将字节解码为unicode字符串。这显然不是更好的选择

相关问题 更多 >