python中struct模块之字节型数据的处理方法


Posted in Python onAugust 27, 2019

简介

这个模块处理python中常见类型数据和Python bytes之间转换。这可用于处理存储在文件或网络连接中的bytes数据以及其他来源。在python中没有专门处理字节的数据类型,建立字节型数据也比较麻烦,我们知道的bytes()函数也只能对无符号整型做处理,并且数据如下(没错,数字为多少就有多少个\x00,我们要是用这种方式来存储大量数据,结果可想而知):

va = bytes(1) # va: '\x00'
vb = bytes(2) # vb: '\x00\x00'
vc = bytes(5) # vc: '\x00\x00\x00\x00\x00'

但在python中str类型中既可以用字符串表示也可以以字节方式表示,所以你定义一个字节型的字符串常量,python是能处理它的:

va = '\x26' # va: '&'

struct处理

字节顺序

一个数据有多个字节表示的时候,字节的顺序不同也就决定了值,在struct中有以下几种字节顺序:

字符 字节顺序 尺寸 对齐方式
@ 本机 本机 本机
= 本机 标准
小端 标准
> 大端 标准
网络 标准

对于字节顺序,只有大端和小端两种方式,只是比如你用@和=代表你用本机的字节顺序,!代表你使用网络的字节顺序。你不指定字节顺序则默认的是@。

本地字节顺序是大端或小端,取决于主机系统。例如,Intel x86和AMD64(x86-64)是小端的; 摩托罗拉68000和PowerPC G5是大端; ARM和Intel Itanium具有可切换的字节序(双字节序)。使用sys.byteorder来检查你的系统的字节顺序。

数据格式

struct支持的打包解包的数据格式如下,我们需要指定格式才能对应处理,其中对应尺寸已列出(以字节为单位):

字符 C类型 python类型 标准尺寸
x 填充字节 没有意义的值
c char 长度为1的字节 1
b signed char 整型 1
B unsigned char 整型 1
_Bool 布尔 1
h short 整型 2
H unsigned short 整型 2
i int 整型 4
I unsigned int 整型 4
l long 整型 4
L unsigned long 整型 4
q long long 整型 8
Q unsigned long long 整型 8
n ssize_t 整型
N size_t 整型
e 浮动 2
f float 浮动 4
d double 浮动 8
s char[] 字节
p char[] 字节
P void * 整型

打包

通过struct的pack(fmt, *args)来实现对各种数据的打包(转换为对应字节数据),pack的需要传递的参数fmt就是数据的格式,包括了字节顺序、数据类型;后面的*args参数是需要打包的数据。

vaa = struct.pack('>I', 1255) # vaa: '\x00\x00\x04\xe7' 1*4=1个字节 vab = struct.pack('>II', 1255, 23) # vab: '\x00\x00\x04\xe7\x00\x00\x00\x17' 2*4=8个字节 vac = struct.pack('>2I?', 1255, 23, True) # vac: '\x00\x00\x04\xe7\x00\x00\x00\x17\x01' 2*4+1=9个字节

我们看上述三个使用例子(数据与数据之间没有填充,都是连续的,比如对于vac我们不知道 它是由两个4字节无符号整型和一个布尔构成,我们就无法取得正确的值),看fmt参数:

‘>I'代表了以大端的字节顺序打包一个4字节无符号整型数据,所以后面只跟了一个无符号整型参数1255;

‘>II'代表了以大端的字节顺序打包两个4字节无符号整型数据,所以后面跟了两个个无符号整型参数1255和23;

‘>2I?'代表了以大端的字节顺序打包两个4字节无符号整型和一个布尔型数据,所以后面跟了两个个无符号整型参数1255、23和一个布尔值True。

注意'2I'和'II','4I'和'IIII','2?'和'??'是一样的效果。

解包

通过struct的unpack(fmt, string)来实现对字符串的解包,fmt和打包的是完全一样的,如下(返回的结果是一个元组):

vaa = struct.pack('>I', 1255) # vaa: '\x00\x00\x04\xe7'
vab = struct.pack('>II', 1255, 23) # vab: '\x00\x00\x04\xe7\x00\x00\x00\x17'
vaaa = struct.unpack('>I', vaa) # vaaa: <class 'tuple'>: (1255, )
vaba = struct.unpack('>II', vab) # vaba: <class 'tuple'>: (1255, 23)

进阶使用

pack_into(fmt, buffer, offset, *args)

fmt参数和pack是一样的,buffer参数是可写的缓存区,offset是写入位置的偏移量,*args是需要写入的数据。这个有什么用呢,我们想想这样两个情况,我们有两个类型已经打包好,我们想在这两个已经打包好的数据后面再添加一个数据打包;或者我们要打包的数据很多,我们不可能在pack中把所有需要打包的数据都通过参数传递给pack,那你的pack函数可能得写成千上完个参数了。这时候我们就可以用到这个函数了。

要使用它必须要一个可以写入的缓存区,我们可以导入一个字符缓存区包,然后创建一个固定大小的缓存区(以字节为单位):

import struct
from ctypes import create_string_buffer

# 创建一个9字节大小的缓存区,初始化默认全部为\x00 
buf = create_string_buffer(9) # buf.raw: '\x00\x00\x00\x00\x00\x00\x00\x00\x00'

# 冲缓存区buf的第0个字节开始打包两个4字节无符号整型数据1和2
struct.pack_into(">II", buf, 0, 1, 2) # buf.raw: '\x00\x00\x00\x01\x00\x00\x00\x02\x00'
# 然后我们想再打包一个布尔型数据到buf中就可以改变以下偏移量
struct.pack_into(">?", buf, 8, True) # buf.raw: '\x00\x00\x00\x01\x00\x00\x00\x02\x01'

unpack_from(fmt, buffer, offset)和calcsize(fmt)结合解包数据

calcsize用于计算格式字符串所对应的结果的长度,如:struct.calcsize(‘II'),返回8。因为两个无符号整型所占用的长度是8个字节。unpack_from(fmt, buffer, offset)用于从buffer缓存区中使用fmt格式从offset偏移量处开始解包fmt里对应数量的数据。

import struct
from ctypes import create_string_buffer

buf = create_string_buffer(9)
struct.pack_into(">II", buf, 0, 1, 2)
struct.pack_into(">?", buf, 8, True)
# 记录位置
pos = 0
# 从buf缓存区中以大端方式从偏移位置pos处解包两个无符号整型数据返回,注意
#返回值如果只写一个则返回一个元组,否则你解包几个数据就要写几个返回值。
val = struct.unpack_from('>II', buf, pos) # val: <class 'tuple'>: (1, 2)
val_a, val_b = struct.unpack_from('>II', buf, pos) # val_a: 1 val_b: 2

# 重置解包位置
pos += struct.calcsize('>II') # pos: 8
val_c, = struct.unpack_from('>?', buf, pos) # val_c: True

示例

这个示例是基于mnist手写数字识别的,我们刚开始有60000张手写数字的图片(.bmp格式的),我们通过下述代码将60000张图片转换成字节型数据,bytes.py代码如下:

import struct
import os
import numpy as np
from ctypes import create_string_buffer
import cv2

# 创建一个60000 * 784 * 1 + 3 * 4字节大小的缓存区,初始化默认全部为\x00
buffer = create_string_buffer(60000 * 784 * 1 + 3 * 4)
def writeBytesData():
 index = 0
 BMP_NUM = 0
 BMP_WIDTH = 28
 BMP_HEIGHT = 28

 # 先保留三个无符号整型的缓存区
 index += struct.calcsize('>III')
 path = 'data/bmp'
 if not os.path.exists(path):
  print('No this dir!')
  return
 list = os.listdir(path)
 for line_bmp in list:
  bmp_path = os.path.join(path, line_bmp)
  if os.path.isdir(bmp_path):
   print('This is not a .bmp')
  else:
   BMP_NUM += 1
   print(BMP_NUM)
   buf = cv2.imread(bmp_path, cv2.IMREAD_GRAYSCALE)
   buf = np.reshape(buf, [784])
   for pos in range(buf.__len__()):
    struct.pack_into('>B', buffer, index, buf[pos])
    index += struct.calcsize('>B')

 # 将保留缓存区的内容填上
 struct.pack_into('>III', buffer, 0, BMP_NUM, BMP_WIDTH, BMP_HEIGHT)
 with open('data/bytes/bytes.bytes', 'wb') as fp:
  fp.write(buffer)


def readFromBytes():
 index = 0
 images = []
 with open('data/bytes/bytes.bytes', 'rb') as fp:
  buffer = fp.read()
  # 解包前三个无符号整型
  bmp_num, bmp_width, bmp_height = struct.unpack_from('>III', buffer, index)

  # 重定位偏移量
  index += struct.calcsize('>III')
  for pos in range(bmp_num):
   img = struct.unpack_from('>784B', buffer, index)
   index += struct.calcsize('>784B')
   # 修改为原来的图片形状
   img = np.array(img, dtype=np.uint8)
   img = np.reshape(img, [bmp_height, bmp_width])
   # 显示图片
   cv2.imshow('bmp', img)
   # 按任意键继续
   cv2.waitKey(0)
   images.append(img)
 return images


writeBytesData()
readFromBytes()

在写入bytes文件的时候有点慢,由于有60000张图片每张要写28 * 28个字节,其中目录结构如下,需要图片的可以去我的下载区下载mnist图片数据集:

bytes.py
data
 bmp
  1.bmp
  2.bmp
  ...
  60000.bmp
 bytes

以上这篇python中struct模块之字节型数据的处理方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
使用python实现baidu hi自动登录的代码
Feb 10 Python
Django返回json数据用法示例
Sep 18 Python
Python切片操作实例分析
Mar 16 Python
Python实现一个服务器监听多个客户端请求
Apr 12 Python
python正则表达式之对号入座篇
Jul 24 Python
Python列表推导式与生成器用法分析
Aug 02 Python
详解Python做一个名片管理系统
Mar 14 Python
Python使用Turtle库绘制一棵西兰花
Nov 23 Python
Python 脚本的三种执行方式小结
Dec 21 Python
将matplotlib绘图嵌入pyqt的方法示例
Jan 08 Python
实例讲解Python中sys.argv[]的用法
Jun 03 Python
Python帮你解决手机qq微信内存占用太多问题
Feb 15 Python
Python的bit_length函数来二进制的位数方法
Aug 27 #Python
使用python将excel数据导入数据库过程详解
Aug 27 #Python
python读取指定字节长度的文本方法
Aug 27 #Python
Django中的cookie和session
Aug 27 #Python
Python3之字节串bytes与字节数组bytearray的使用详解
Aug 27 #Python
Python如何应用cx_Oracle获取oracle中的clob字段问题
Aug 27 #Python
在Python中获取操作系统的进程信息
Aug 27 #Python
You might like
人尽可用的Windows技巧小贴士之下篇
2007/03/22 PHP
30个php操作redis常用方法代码例子
2014/07/05 PHP
php递归函数怎么用才有效
2018/02/24 PHP
php集成开发环境详解
2019/09/24 PHP
麦鸡的TAB切换功能结合了javascript和css
2007/12/17 Javascript
使用js画图之画切线
2015/01/12 Javascript
超级给力的JavaScript的React框架入门教程
2015/07/02 Javascript
JSON与XML优缺点对比分析
2015/07/17 Javascript
php输出全部gb2312编码内的汉字方法
2017/03/04 Javascript
简单快速的实现js计算器功能
2017/08/17 Javascript
详解在Vue中有条件地使用CSS类
2017/09/30 Javascript
vue2单元测试环境搭建
2018/05/24 Javascript
使用vue脚手架(vue-cli)搭建一个项目详解
2019/05/09 Javascript
微信小程序 Storage更新详解
2019/07/16 Javascript
vue 中的 render 函数作用详解
2020/02/28 Javascript
[05:04]完美世界携手游戏风云打造 卡尔工作室地图界面篇
2013/04/23 DOTA
Python实现抓取网页并且解析的实例
2014/09/20 Python
人脸识别经典算法一 特征脸方法(Eigenface)
2018/03/13 Python
tensorflow 加载部分变量的实例讲解
2018/07/27 Python
Python功能点实现:函数级/代码块级计时器
2019/01/02 Python
Python3中_(下划线)和__(双下划线)的用途和区别
2019/04/26 Python
详解python实现数据归一化处理的方式:(0,1)标准化
2019/07/17 Python
python从zip中删除指定后缀文件(推荐)
2019/12/05 Python
python 实现批量图片识别并翻译
2020/11/02 Python
美国最佳在线航班预订网站:LookupFare
2019/03/26 全球购物
澳大利亚珠宝商:Shiels
2019/10/06 全球购物
物理系毕业生自荐信
2013/11/01 职场文书
厨师岗位职责
2013/11/12 职场文书
媒矿安全生产承诺书
2014/05/23 职场文书
食品安全处置方案
2014/06/14 职场文书
护理专科学生自荐书
2014/07/05 职场文书
2014年学校党建工作总结
2014/11/11 职场文书
会计工作能力自我评价
2015/03/05 职场文书
小区保洁员岗位职责
2015/04/10 职场文书
总经理聘用协议书
2015/09/21 职场文书
CSS3实现的侧滑菜单
2021/04/27 HTML / CSS