Python fileinput.hook_compressed有时给我字符串,有时给我字节
我正在尝试从许多文件中读取行。有些是gzip文件,有些是纯文本文件。在Python2.7中,我一直在使用以下代码,并且效果良好: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,它仍然可以处理纯文本文件,但
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)