当前位置: 首页 > wzjs >正文

永仁县建设信息网站廊坊做网站教程

永仁县建设信息网站,廊坊做网站教程,对网站开发与管理的分析,宁波seo外包优化文件与 IO(三) 9.读取二进制数据到可变缓冲区中(⭐⭐⭐)9.1 readinto9.2 memoryview9.2.1 零复制9.2.2 与传统方式的对比传统方式(非零复制)零复制方式(memoryview) 9.2.3 总结 10.内…

文件与 IO(三)

  • 9.读取二进制数据到可变缓冲区中(⭐⭐⭐)
    • 9.1 readinto
    • 9.2 memoryview
      • 9.2.1 零复制
      • 9.2.2 与传统方式的对比
        • 传统方式(非零复制)
        • 零复制方式(memoryview)
      • 9.2.3 总结
  • 10.内存映射的二进制文件(⭐⭐⭐)

9.读取二进制数据到可变缓冲区中(⭐⭐⭐)

你想直接读取二进制数据到一个可变缓冲区中,而不需要做任何的中间复制操作。或者你想原地修改数据并将它写回到一个文件中去。

9.1 readinto

为了读取数据到一个可变数组中,使用文件对象的 readinto() 方法。比如:

import os.pathdef read_into_buffer(filename):buf = bytearray(os.path.getsize(filename))with open(filename, 'rb') as f:f.readinto(buf)return buf

下面是一个演示这个函数使用方法的例子:

>>> # Write a sample file
>>> with open('sample.bin', 'wb') as f:
...     f.write(b'Hello World')
...
>>> buf = read_into_buffer('sample.bin')
>>> buf
bytearray(b'Hello World')
>>> buf[0:5] = b'Hello'
>>> buf
bytearray(b'Hello World')
>>> with open('newsample.bin', 'wb') as f:
...     f.write(buf)
...
11
>>>

文件对象的 readinto() 方法能被用来为预先分配内存的数组填充数据,甚至包括由 array 模块或 numpy 库创建的数组。

和普通 read() 方法不同的是, readinto() 填充已存在的缓冲区,而不是为新对象重新分配内存再返回它们。因此,你可以使用它来避免大量的内存分配操作。比如,如果你读取一个由相同大小的记录组成的二进制文件时,你可以像下面这样写:

record_size = 32 # Size of each record (adjust value)buf = bytearray(record_size)
with open('somefile', 'rb') as f:while True:n = f.readinto(buf)if n < record_size:break# Use the contents of buf...

使用 f.readinto() 时需要注意的是,你必须检查它的返回值,也就是实际读取的字节数。

如果字节数小于缓冲区大小,表明数据被截断或者被破坏了(比如你期望每次读取指定数量的字节)。

最后,留心观察其他函数库和模块中和 into 相关的函数(比如 recv_into()pack_into() 等)。Python 的很多其他部分已经能支持直接的 I/O 或数据访问操作,这些操作可被用来填充或修改数组和缓冲区内容。

9.2 memoryview

9.2.1 零复制

另外有一个有趣特性就是 memoryview,它可以通过 零复制 的方式对已存在的缓冲区执行切片操作,甚至还能修改它的内容。

🚀 零复制(Zero-Copy)是一种 高效的数据处理技术,它允许程序 直接访问数据缓冲区,而无需在内存中复制数据。传统的数据操作(如切片、修改)通常需要先复制一份数据,而零复制技术避免了这一额外开销,从而提升性能并减少内存占用。

Python 的 memoryview 对象提供了一种零复制的方式来操作现有的缓冲区(如 bytesbytearraymmap 等),允许:

  1. 直接引用原始数据,而无需复制。
  2. 修改原始数据(如果底层缓冲区可写,如 bytearray)。
  3. 高效切片,即使操作大型数据也不会产生额外内存消耗。

比如:

>>> buf
bytearray(b'Hello World')
>>> m1 = memoryview(buf)
>>> m2 = m1[-5:]
>>> m2
<memory at 0x100681390>
>>> m2[:] = b'WORLD'
>>> buf
bytearray(b'Hello WORLD')
>>>

1. 创建 bytearray 缓冲区

buf = bytearray(b'Hello World')  # 可变的字节数组
  • buf 是一个可修改的 bytearray,内容为 b'Hello World'

2. 创建 memoryview 对象

m1 = memoryview(buf)  # 零复制方式引用 buf
  • m1buf 的零复制视图,不复制数据,直接操作 buf 的内存。

3. 对 memoryview 切片(零复制)

m2 = m1[-5:]  # 获取最后 5 字节的视图(' World')
  • m2m1 的一个切片,仍然零复制,不会创建新数据副本。
  • 此时 m2 的内容是 b'World'(但底层仍指向 buf 的对应部分)。

4. 通过 memoryview 修改原始数据

m2[:] = b'WORLD'  # 修改 m2 的内容
  • m2 的内容替换为 b'WORLD',由于 m2 是零复制视图,直接修改了 buf
  • 最终 buf 变为 bytearray(b'Hello WORLD')

9.2.2 与传统方式的对比

传统方式(非零复制)
buf = bytearray(b'Hello World')
sliced = buf[-5:]  # 复制数据,生成新对象
sliced = b'WORLD'  # 修改的是副本,不影响 buf
print(buf)  # 仍为 b'Hello World'(未改变)
  • 切片会复制数据,修改副本不影响原始数据。
零复制方式(memoryview)
buf = bytearray(b'Hello World')
m = memoryview(buf)
m[-5:][:] = b'WORLD'  # 直接修改原始数据
print(buf)  # 输出 b'Hello WORLD'
  • 切片和修改均直接作用于原始数据。

9.2.3 总结

  • 零复制:通过 memoryview 直接操作原始缓冲区,避免数据拷贝。
  • memoryview 的作用
    • 提供对缓冲区的零复制访问。
    • 支持高效切片和修改(若底层可写)。
  • 适用场景:需要高性能、低内存占用的二进制数据处理任务。

10.内存映射的二进制文件(⭐⭐⭐)

你想 内存映射一个二进制文件到一个可变字节数组中,目的可能是为了随机访问它的内容或者是原地做些修改。

使用 mmap 模块来内存映射文件。下面是一个工具函数,向你演示了如何打开一个文件并以一种便捷方式内存映射这个文件。

import os
import mmapdef memory_map(filename, access=mmap.ACCESS_WRITE):size = os.path.getsize(filename)fd = os.open(filename, os.O_RDWR)return mmap.mmap(fd, size, access=access)
  • access:访问模式,默认 mmap.ACCESS_WRITE(可读写),其他选项:
    • mmap.ACCESS_READ(只读)
    • mmap.ACCESS_COPY(写操作不修改原文件,仅修改内存副本)
  • os.path.getsize(filename):返回文件大小(字节数),用于确定内存映射的大小。
  • os.open(filename, os.O_RDWR)
    • os.open()open() 更底层,返回文件描述符 fd(整数)。
    • os.O_RDWR:以读写模式打开文件。
  • mmap.mmap(fd, size, access=access)
    • fd:文件描述符。
    • size:映射的字节数(通常等于文件大小)。
    • access:访问权限(如 mmap.ACCESS_WRITE)。
  • 返回一个 mmap 对象,可以像操作 bytesbytearray 一样操作文件数据。

为了使用这个函数,你需要有一个已创建并且 内容不为空 的文件。下面是一个例子,教你怎样初始创建一个文件并将其内容扩充到指定大小:

>>> size = 1000000
>>> with open('data', 'wb') as f:
...     f.seek(size-1)
...     f.write(b'\x00')
...
>>>
  • f.seek(N) 将文件指针移动到第 N 个字节(从 0 开始计数)。
  • 这里移动到 size - 1(即第 999,999 字节),因为我们要在最后写入 1 字节。
  • b'\x00' 是一个值为 0 的字节(即空字节)。
  • 写入后,文件大小变为 size(1,000,000 字节),未显式写入的部分会自动填充 \x00

下面是一个利用 memory_map() 函数类内存映射文件内容的例子:

>>> m = memory_map('data')
>>> len(m)
1000000
>>> m[0:10]
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
>>> m[0]
0
>>> # Reassign a slice
>>> m[0:11] = b'Hello World'
>>> m.close()>>> # Verify that changes were made
>>> with open('data', 'rb') as f:
... print(f.read(11))
...
b'Hello World'
>>>

mmap() 返回的 mmap 对象同样也可以作为一个上下文管理器来使用,这时候底层的文件会被自动关闭。比如:

>>> with memory_map('data') as m:
...     print(len(m))
...     print(m[0:10])
...
1000000
b'Hello World'
>>> m.closed
True
>>>

默认情况下,memeory_map() 函数打开的文件同时支持读和写操作。任何的修改内容都会复制回原来的文件中。

如果需要只读的访问模式,可以给参数 access 赋值为 mmap.ACCESS_READ。比如:

m = memory_map(filename, mmap.ACCESS_READ)

如果你想在本地修改数据,但是又不想将修改写回到原始文件中,可以使用 mmap.ACCESS_COPY

m = memory_map(filename, mmap.ACCESS_COPY)

为了随机访问文件的内容,使用 mmap 将文件映射到内存中是一个高效和优雅的方法。例如,你无需打开一个文件并执行大量的 seek()read()write() 调用, 只需要简单的映射文件并使用切片操作访问数据即可。

一般来讲, mmap() 所暴露的内存看上去就是一个二进制数组对象。但是,你可以使用一个内存视图来解析其中的数据。比如:

>>> m = memory_map('data')
>>> # Memoryview of unsigned integers
>>> v = memoryview(m).cast('I')
>>> v[0] = 7
>>> m[0:4]
b'\x07\x00\x00\x00'
>>> m[0:4] = b'\x07\x01\x00\x00'
>>> v[0]
263
>>>

1. 内存映射文件

m = memory_map('data') 
  • memory_map('data') 将文件 data 映射到内存,返回一个 mmap 对象 m,可以像 bytes 一样操作。

2. 创建 memoryview 并转换为无符号整数('I'

v = memoryview(m).cast('I')
  • memoryview(m) 创建一个内存视图,允许以不同方式解释底层数据。
  • .cast('I') 将数据解释为 无符号整数(unsigned int,4字节)
    • 'I'struct 模块的格式字符,表示 4 字节无符号整数(小端序)。
    • 此时 v 是一个无符号整数数组,可以直接通过索引访问/修改。

3. 修改无符号整数值

v[0] = 7
  • 将第一个无符号整数(v[0],对应 m[0:4])设为 7
  • 写入后,m[0:4] 的字节变为 b'\x07\x00\x00\x00'(小端序)。

4. 查看底层字节

m[0:4]
  • 输出 b'\x07\x00\x00\x00',即:
    • 十六进制:0x07 0x00 0x00 0x00(小端序表示 7)。

5. 直接修改字节数据

m[0:4] = b'\x07\x01\x00\x00'
  • 直接通过 mmap 对象修改前 4 字节为 b'\x07\x01\x00\x00'(小端序)。

6. 查看无符号整数值

v[0]
  • 输出 263,因为:
    • b'\x07\x01\x00\x00' 在小端序下解析为 0x00000107 = 263

示例扩展
假设文件 data 初始内容为 b'\x00\x00\x00\x00\x00\x00\x00\x00'(8字节全0):

# 映射文件并转换为无符号整数数组
m = memory_map('data')  # 假设文件大小为 8 字节
v = memoryview(m).cast('I')# 修改前两个整数
v[0] = 7       # m[0:4] = b'\x07\x00\x00\x00'
v[1] = 263     # m[4:8] = b'\x07\x01\x00\x00'# 验证
print(m[0:8])  # 输出 b'\x07\x00\x00\x00\x07\x01\x00\x00'
print(v[0], v[1])  # 输出 7, 263

需要强调的一点是,内存映射一个文件并不会导致整个文件被读取到内存中。也就是说,文件并没有被复制到内存缓存或数组中。相反,操作系统仅仅为文件内容保留了一段虚拟内存。当你访问文件的不同区域时,这些区域的内容才根据需要被读取并映射到内存区域中。而那些从没被访问到的部分还是留在磁盘上。所有这些过程是透明的,在幕后完成!

如果多个 Python 解释器内存映射同一个文件,得到的 mmap 对象能够被用来在解释器直接交换数据。也就是说,所有解释器都能同时读写数据,并且其中一个解释器所做的修改会自动呈现在其他解释器中。很明显,这里需要考虑同步的问题。但是这种方法有时候可以用来在管道或套接字间传递数据。

这一小节中函数尽量写得很通用,同时适用于 Unix 和 Windows 平台。要注意的是使用 mmap() 函数时会在底层有一些平台的差异性。
另外,还有一些选项可以用来创建匿名的内存映射区域。如果你对这个感兴趣,确保你仔细研读了 Python 文档中 这方面的内容 。

http://www.dtcms.com/wzjs/538589.html

相关文章:

  • 西宁做网站最好的公司佛山网站设计
  • 丽水建设局门户网站平台型网站制作
  • 宁波龙山建设有限公司网站国外c2c平台
  • 网站推广怎么做与发布江西泰飞建设有限公司网站
  • 织梦做淘宝客网站视频教程WordPress代码实现标签页面
  • 苏州优化网站哪家好wordpress页面禁止评论
  • 西宁设计网站建设wordpress 函数重写
  • unas做网站服务器深圳网站开发服务
  • 国际电子商务网站建设建网站都要什么费用
  • 如何管理wordpress网站模板论坛网站建设需要多少钱
  • 莱芜建设银行网站wordpress文章百度主动推送
  • 自助外贸英文网站建设建设个直播网站要多少钱
  • 网站代发怎么做从零开始做网站seo
  • 开发菏泽网站建设东莞市外贸网站建设公司
  • 安徽网站开发哪家好香奈儿vi设计手册
  • 商城系统网站建设开发天津市住房和城乡建设厅官网
  • 企业网站傻瓜搭建广东省路桥建设发展有限公司网站
  • 珠海网站建设 骏域网站企业网站html5
  • 在网站怎么做代销物流企业网站建设方案
  • 镇江网站建设介绍服务营销型网站的评价
  • 郑州做网站公司 卓美小型教育网站的开发与建设
  • 建设银行网站官方网站cms开源建站系统
  • 网站建设的七个流程步骤wordpress 设置显示中文字体
  • 网站建设 海外房产固定ip 建网站
  • 有没有在家做的手工活网站浙江金圣建设有限公司网站
  • 网站开发需要哪些资料动漫制作专业必须会画画吗
  • 网站被k怎么办163企业邮箱怎么开通注册账号
  • 哪个网站可以免费看小说不收费网站建设工作室 怎么样
  • 微信绑定网站员工培训内容
  • 腾讯快速建站平台wordpress主题压缩包