在 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()
函数的文档:
Read at most n characters from stream.
Read from underlying buffer until we have n characters or we hit EOF. If n is negative or omitted, read until EOF.
如果是这样,第一行 bytestream.read(16)
的功能角色将必须读取并因此跳过前 16 个字符,大概是因为它们充当元数据或标题。但是,当我有一些图像时,我怎么知道使用 16
作为 read
调用的参数,而不是 32、8 或 64?
我记得有很多次遇到与上面完全相同的代码,除了作者使用 bytestream.read(8)
而不是 bytestream.read(16)
或者只是可能,任何其他值。逐个字符地深入文件显示没有可识别的模式来确定标题字符的长度。
换句话说,如何确定要在 read
函数调用中使用的参数? 或者如何知道 gzip 中标题字符的长度-压缩文件?
我的猜测是它与字节有关,但在搜索文档和在线引用资料后我无法证实这一点。
可重现的细节
我的假设是,经过无数小时的故障排除后,前 16 个字符代表某种标题或元数据。所以该代码的第一行是跳过 16 个字符并将剩余的字符存储在名为 buf
的变量中。但是,通过深入研究数据,我发现无法确定为什么或如何选择值 16。我已经逐个字符地读取字节,也尝试读取 + 将它们转换为 np.float
,但是没有明显的模式表明元数据在第 16 个字符和实际数据处结束17日开始。
以下代码从this website中读取数据并提取前 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 的角度来看,它返回给您的一切都是数据。 没有该数据流前面没有元数据或特定于 gzip 的 header 内容,因此不需要任何类型的算法来计算 gzip 为该流添加了多少内容:它的字节数前置为零。
向下滚动到您链接的页面底部;有一个标题为 FILE FORMATS FOR THE MNIST DATABASE 的标题。
该格式规范准确地告诉您格式是什么,以及每个 header 使用了多少字节。具体来说,每个文件中的前四项描述如下:
0000 32 bit integer 0x00000803(2051) magic number
0004 32 bit integer 60000 number of images
0008 32 bit integer 28 number of rows
0012 32 bit integer 28 number of columns
因此,如果您想跳过所有这四个项目,您需要从顶部移除 16 个字节。
关于python - gzip.open().read() 的大小参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54019755/