在Python中使用gzip库时,我经常会遇到使用.read()
函数的代码模式,看起来像这样:
with gzip.open(filename) as bytestream:
bytestream.read(16)
buf = bytestream.read(
IMAGE_SIZE * IMAGE_SIZE * num_images * NUM_CHANNELS
)
data = np.frombuffer(buf, dtype=np.uint8).astype(np.float32)
虽然我熟悉上下文管理器设计模式,但我很难真正理解 with
上下文管理器中第一行代码在做什么。
这是 read()
函数的文档:
从流中最多读取 n 个字符。
从底层缓冲区读取,直到我们有 n 个字符或遇到 EOF。 如果 n 是负数或省略,则读取直到 EOF。
如果是这样,那么第一行代码 bytestream.read(16)
的功能作用应该是读取并跳过前面的 16 个字符,这些字符可能充当元数据或标头。然而,当我有一些图像时,我怎么知道要在 read
调用中使用参数 16
,而不是例如 32
,8
或 64
呢?
我记得很多次看到完全相同的代码,除了作者使用 bytestream.read(8)
而不是 bytestream.read(16)
,或者同样有可能使用任何其他值。逐个字符地挖掘文件没有明显的模式可以确定标头字符的长度。
换句话说,如何确定 read
函数调用使用的参数? 或者如何知道 gzip 压缩文件中标头字符的长度?
我猜想它与字节有关,但在搜索文档和在线参考资料后,我无法确认。
可重现的细节
经过无数小时的疯狂排错,我的假设是前面的 16 个字符表示某种标题或元数据。因此,该代码中的第一行是为了跳过这 16 个字符并将其余部分存储在名为 buf
的变量中。然而,在挖掘数据时,我发现没有办法确定选择值为 16 的原因或方式。我逐个字符读取了字节,并尝试将它们读取并转换为 np.float
,但没有明显的模式表明元数据在第 16 个字符结束,实际数据从第 17 个字符开始。
以下代码从此网站读取数据并提取前 30 个字符。请注意,标头行的“结尾”(显然是第 16 个 \x1c` 出现后)和数据从哪里开始不可辨认:
import gzip
import numpy as np
train_data_filename = 'data_input/train-images-idx3-ubyte.gz'
IMAGE_SIZE = 28
NUM_CHANNELS = 1
def extract_data(filename, num_images):
with gzip.open(filename) as bytestream:
first30 = bytestream.read(30)
return first30
first30= extract_data(train_data_filename, 10)
print(first30)
# returns: b'\x00\x00\x08\x03\x00\x00\xea`\x00\x00\x00\x1c\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
如果我们修改代码将它们转换为np.float32
,使得所有字符现在都是数字(浮点数),那么似乎没有明显的模式可以区分头部/元数据结束和数据开始的位置。
任何参考或建议都将不胜感激!
gzip.open(...).read()
只会返回(从gzip的角度来看)数据内容 - 根本没有返回任何gzip特定的元数据。 - Charles Duffy