Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python fileinput.hook_compressed有时给我字符串,有时给我字节_Python_File_Python 3.8 - Fatal编程技术网

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

Python fileinput.hook_compressed有时给我字符串,有时给我字节,python,file,python-3.8,Python,File,Python 3.8,我正在尝试从许多文件中读取行。有些是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文件,有些是纯文本文件。在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的代码。

根据它是否获得Gzip文件,做了根本不同的事情。对于文本文件,它使用常规打开,默认情况下,它实际上以文本模式打开。例如,默认模式是二进制,这对于未知内容的压缩文件是合理的

只有二进制的限制是由人工施加的。根据方法代码:

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

选项1

\uuuu init\uuuu
之后设置
\u模式
属性。为了避免在用法中添加额外的代码行,您可以将
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字符串。这显然不是最好的选择。

您是否尝试过
mode='rt'
?@HeapOverflow。不幸的是,“[模式]必须是‘r’、‘rU’、‘U’和‘rb’中的一种。”@Madah。我只查看了
open
gzip.open
的选项。可怜。我猜他们将不得不编写自己的钩子…我想知道,根据我读到的,
fileinput。input
默认情况下应该使用
mode='r'
(覆盖
gzip
的默认
'rb'
)。@mkrieger1。当您将
r
传递给gzip时,它默认为二进制谢谢。但是,的文档没有提到允许使用文本模式;另一方面,是的,所以您的答案应该使用bz2.open。但不管怎样,这只在Python3.8中起作用,因为Python2.7不允许将“t”作为模式(对于bz2或gzip)。所以我必须检查sys.version,如果是2,则使用fileinput.hook_compressed,否则使用my_hook_compressed-这有点不规范。@k314159。不幸的是,Python2和Python3之间存在不可调和的差异,包括字符串的编码和解码。我已经修复了对
bz2.open
的调用,因为您的参数在这方面是正确的。原始代码是源代码中实现的直接副本,添加了一条
if
语句。这里的目标不是提供一个有生产价值的实现,只是为了说明一些选项。谢谢。顺便说一下,选项1应该为TextFileInput(filenames,mode='rt',openhook=fileinput.hook_compressed)中的行显示
?@k314159。对而现在它做到了。谢谢你的提醒:)
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)