在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个字符,大概是因为它们充当了元数据或标头。但是,当我有一些图像时,我怎么知道使用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
,以使所有字符现在都为数字(浮点数),那么就再也没有明显的模式来区分标头/元数据的结束位置和数据的位置开始。
任何参考或建议将不胜感激!
答案 0 :(得分:1)
从gzip的角度来看,它返回给您的一切都是数据。该数据流中没有 元数据或特定于gzip的标头内容,因此不需要任何算法来计算gzip在该流中前置多少内容:它的字节数prepends为零。
向下滚动到链接页面的底部;有一个标题为 MNIST数据库的文件格式的标题。
该格式规范会准确告诉您什么格式,以及每个头使用多少字节。具体来说,每个文件中的前四项描述如下:
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个字节。
答案 1 :(得分:0)
bytestream.read(16)
从代码片段读取或跳过字节流的前16个字节。当您引用read()从流中读取最多n个字符时,它会这样做,但是似乎python在1个字节中存储一个字符,使16个字符占用16个字节。
有关字符和字节https://pymotw.com/3/gzip/#reading-compressed-data
的更多信息代码片段主要对buf的内容感兴趣,跳过了流的前16个字节。要了解如何确定首先进入bytestream.read()
AKA的参数来确定要跳过的压缩图像文件的字节数,我们必须了解其余代码的作用。特别是,我们正在读取什么文件,并试图使用numpy(?)库完成什么(将rgb图像保存在一维numpy数组中?)。
我绝对不是图像处理专家,但是看来bytestream.read(16)
是解决某些独特压缩图像文件的独特问题的独特解决方案。因此,很难知道如何确定要跳过多少个字节,而又看不到更多代码,也不能理解代码片段后面的更多逻辑。