前言:

背景:很多时候我们需要用python处理二进制数据。例如,存储文件、进行socket操作等。这个时候就需要用到struct模块。

struct用途:

(1)按照指定格式将Python数据转换为字符串(字节流)。如网络传输时不能直接传输int/long数据,此时要先将int/long转化为字节流,然后再发送;
(2)按照指定格式将字节流转换为Python指定的数据类型;
(3)处理二进制数据,如果用struct来处理文件的话,需要用’wb’,’rb’以二进制(字节流)写,读的方式来处理文件;
(4)处理C或者C++语言中的结构体;

接下来我们介绍struct模块中最重要的pack,unpack两个函数。

注:例如二进制流与数值的互相转换在编解码、开发小工具方面用途非常广泛。

二、struct模块

1、pack()函数

#按照给定的格式(format),把数据封装成字符串(实际上是类似于C结构体的字节流)
pack(format,v1,v2,...)

2、unpack()函数

#按照给定的格式(format),解析字节流string,返回解析出来的tuple
pack(format,string)

3、calcsize()函数

#计算给定的格式(format)占用多少字节的内存。
#注:icc表示三个成员数据类型是interger, char, char。
size = struct.calcsize(’@icc’) 结果是6。
size = struct.calcsize(’@cic’) 结果是9。

4、上述format支持的格式参见末尾表格。关于格式有如下几点说明:

(1)每个格式前面可以带一个数字,表示个数;

(2)s格式表示一定长度的字符串,4s表示长度为4的字符串;

(3)P用来转换一个指针,其长度和机器字长相关;

5、为了同C结构体交换数据还要考虑C或者C++编译器用到的字节对齐。字节序和对齐方式有如下5种:

Character Byte order Size Alignment
@(默认) 本机 本机 本机,凑够4字节
= 本机 标准 none,按原字节数
< 小端 标准 none,按原字节数
> 大端 标准 none,按原字节数
! network(大端) 标准 none,按原字节数

(1)Byte order列中的native(本机)表示和当前系统的字节序一致;

(2)size列的native(本机)表示这个时候数据类型的大小和sizeof一致;如果是standard(标准)表示数据类型的长度是固定的;

(3)alignment是native(本机)的时候表示和当前系统的字节对齐方式一致。但是要注意的是python中的字节填充(padding)只会在连续的结构体成员之间添加,不会在结构体的开头和结尾添加。例如:

size = struct.calcsize(’@icc’) 结果是6。
size = struct.calcsize(’@cic’) 结果是9。

原因是系统字节对齐是4,第一个c和i之间添加了3个字节padding,但是最后一个c,后边没有添加padding,所以结果是9而不是12。

1)如何解决这个问题?当然有办法,在格式字符串的最后添加一个“0X”,“X”是一个数据类型,如“i”,代表的就是long,这时候就是指定数据类型,这时候就和C语言中的字节对齐完全一致。
size = size = struct.calcsize(’@cic0i’) 结果是12。

2)举个例子
在C代码中定义结构体:
Struct Person{
int fortune;
char height;
char weight;
};
假设从C代码中获取到的结构体数据是buf, 在python中使用struct模块按照上述的格式解析结构体中的数据。
python中使用struct.unpack(’@icc’, buf);解析结构体数据,这个时候就会报错。原因就是字节对齐导致两方的长度不一样。
size = struct.calcsize(’@icc’) 的结果是6,而sizeof(Person)的长度是8。这样就会导致解析错误。这是后需要指定格式对齐。
struct.unpack("@icc0i",buf)。这样就能正确解析C语言中的结构体。

(4)默认情况下使用字节序且对齐字符即表格中的”@“。

(5)对于涉及到socket收发的情况我们一般用”i“,即网络字节序。

三、使用举例

1、首先要明白不同类型数据的自然边界对齐值,如下:

数据类型

对齐值

char

1

short

2

int

4

long

4(8,64位)

float

4

double

8

void *

4(8,64位)

注意:如果一个结构体全部由char组成,也就是说其对齐值为1;此时完全没有担心字节对齐引发问题的必要了。

2、可以随心所欲的在C/C++的结构体之前来回解析与转换(也就是说socket发送C结构体其实一样很好操作)

比如有如下一个结构体

struct Header
{unsigned short id;char[4] tag;unsigned int version;unsigned int count;
}

通过socket.recv接收到这个结构体buf的时候需要要把它解析出来,此时就可以使用unpack函数。

import struct
#'!'表示我们用网络字节序解析,因为我们是从网络上接收到这个buf的。
#'H'表示unsigned short的id;
#'4s'表示四个字节长的字符串;
#'2I'表示有两个unsigned int类型的数据;
id,tag,version,count = struct.unpack('!H4s2I',buf)

同样我们也可以很方便的把本地数据在pack成struct格式。

buf = struct.pack('!H4s2I',id,tag,version,count)

pack函数就是把四个参数按照指定的格式转换成了结构体Header,buf现在是一个字符串(实际上类似于C结构体的字节流),这个字节流是可以通过socket.send(buf)发送出去的。接受者按照上面unpack的方法就可以还原出原始的四个参数。

3、举例二:

a='hello'
b='world!'
c=2
d=45.123
bytes=struct.pack('5s6sif',a,b,c,d)

此时的bytes就是二进制形式的数据了,可以直接写入文件比如 binfile.write(bytes);
当我们需要时可以再读出来,bytes=binfile.read()
再通过struct.unpack()解码成python变量

a,b,c,d=struct.unpack('5s6sif',bytes)

'5s6sif'这个叫做fmt,就是格式化字符串,由数字加字符构成,5s表示占5个字符的字符串,2i,表示2个整数等等,下面是可用的字符及类型,ctype表示可以与python中的类型一一对应。

struct的format支持的格式:

Format C Type Python type Standard size Notes
x pad byte no value    
c char string of length 1 1  
b signed char integer 1 (3)
B unsigned char integer 1 (3)
? _Bool bool 1 (1)
h short integer 2 (3)
H unsigned short integer 2 (3)
i int integer 4 (3)
I unsigned int integer 4 (3)
l long integer 4 (3)
L unsigned long integer 4 (3)
q long long integer 8 (2), (3)
Q unsigned long long integer 8 (2), (3)
f float float 4 (4)
d double float 8 (4)
s char[] string 1  
p char[] string    
P void * integer   (5), (3)

python使用struct处理二进制数据(使用pack和unpack进行打包和解包)相关推荐

  1. Python 读写文件的二进制数据

    概述 Python 读写文件的二进制数据比 C/C++ 语言复杂得多.主要差别在于需要进行 bytes 类型和其它基础数据类型(比如 int/float)的转换. 转换工具在一般情况下都是使用 str ...

  2. Python赋值、打包和解包,90%人不清楚的知识点!

      人生苦短,快学Python! 关于赋值.打包和解包这 3个概念,我觉得有必要做一个分享,因为很多朋友确实不清楚. 如果有这样一个元组t: >> t = ('foo', 'bar', ' ...

  3. Python使用struct处理二进制

    有的时候需要用python处理二进制数据,比如,存取文件,socket操作时.这时候,可以使用python的struct模块来完成.可以用 struct来处理c语言中的结构体. struct模块中最重 ...

  4. Python使用struct处理二进制(转)

    转自:https://www.cnblogs.com/gala/archive/2011/09/22/2184801.html 有的时候需要用python处理二进制数据,比如,存取文件,socket操 ...

  5. Python - 文本字符串、二进制数据

    文本字符串 1. Unicode 1.1 Unicode字符串 Python3的字符串是Unicode字符串不是字节数组.这是与python2相比最大的差别. 用\u及4个十六进制的数字可以从Unic ...

  6. Python从入门到实践:打包和解包(*和**)的使用

    目录 一.打包参数 二.解包参数 三.几点注意 *和**在函数的定义和调用阶段,有着不同的功能,并且,*和**不能离开函数使用! 一.打包参数 * 的作用:在函数定义中,收集所有位置参数到一个新的元组 ...

  7. python基础第五课--从字符串中打包和解包大整数(小白piao分享)

    #4.从字符串打包和解包大整数 #将一个字符串解包成一个大整数,将一个大整数打包成一个字符串 #4.1 解决方案: #假设程序需要处理一个有16个元素的字节串,其中保存着一个128位的大整数 data ...

  8. PHP: chr和pack、unpack那些事

    为什么80%的码农都做不了架构师?>>>    PHP是一门很灵活的语言.正因为它太灵活了,甚至有些怪异,所以大家对它的评价褒贬不一.其实我想说的是,任何一门语言都有它自身的哲学,有 ...

  9. python解析C/C++结构体二进制数据

    一.引言 socket为数据通信中必不可少的一部分,常用的有TCP数据传输协议和UDP数据传输协议.(具体的socket详情这里不赘述). 不论是TCP还是UDP,凡是涉及到数据传输,都需要进行数据内 ...

  10. Python之struct介绍及详解(与C/C++通信结构体的交互)

    用处 按照指定格式将Python数据转换为字符串,该字符串为字节流,如网络传输时,不能传输int,此时先将int转化为字节流,然后再发送; 按照指定格式将字节流转换为Python指定的数据类型; 处理 ...

最新文章

  1. C/C++在不确定输入字符串长度情况下,对其进行存储和字符操作问题
  2. linux下配置java
  3. clickhouse物化视图优缺点_ClickHouse 适用场景
  4. MMU内存管理单元(看书笔记)
  5. Mac如何设置Vamare Fusion虚拟集的vmnet-8网卡
  6. 公钥、私钥、数字签名、数字证书、对称与非对称算法、HTTPS
  7. gnome扩展_GNOME桌面的12个扩展
  8. 格力电器:回购股份比例超3% 已耗资95.15亿元
  9. java 五大原则_面向对象五大原则
  10. @vail 判断某字段在范围内_条件判断函数If,你真的会使用吗?实用技巧都掌握吗?...
  11. 广西高中有没有计算机课程,广西普通高中学业水平考试信息技术学科-广西招生考试院.doc...
  12. webgame源码下载及网页游戏开发资源精华集合
  13. 如何解压 GZ 文件
  14. IIC数据总线 线与 还是 线或 ?是线与
  15. 银联收单清算体系和处理流程
  16. 计算机保研面试英文,计算机保研面试英文自我介绍范文
  17. Unity 制作简单的任务动画
  18. Vue this.$router.go(0) 刷新当前页面在苹果手机无效
  19. C语言到底有多强大?
  20. 自动驾驶3-1: 自动驾驶汽车的安全保障 Safety Assurance for Self-Driving Vehicles

热门文章

  1. rk3399 io工具的使用示例
  2. Ubuntu中创建、删除、更改、移动文件的命令
  3. Oracle 自定义函数、存储过程
  4. XJOI 3281 A * B Problem again 题解
  5. Nginx负载均衡与反向代理——基础功能
  6. PHPExcel如何把该列的值设置为文本无科学计数?
  7. modelsim+win环境下systemverilog调用c函数
  8. Javascript语言精粹--The Excellence in Javascript
  9. VMware 安装 CentOS 7
  10. html div重叠上方,html – 将父div上方的子div对齐到右边,不要重叠