#!/usr/bin/env python
#-*- coding:utf-8 -*-
'''
Name:HD
'''
r'''
    有的时候需要用python处理二进制数据,比如村粗文件,socket操作时,这时候可以使用python的struct模块来完成,可以使用struct来处理c语言中的结构体:
struct模块中最重要的三个函数:
        1.pack(fmt,v1,v2,....) #按照给定的格式(fmt),把数据封装成字符串(类似于c结构体的字节流)
        2.unpakc(fmt,string)  #按照给定的格式(fmt)解析字节流,返回接续出来的tuple
        3.calcsize(fmt) 计算给定的格式(fmt)占用多少字节的内存

    struct 中支持的格式:

        +----------------------------------------------------------------+
        |  Format  |    其他语言的结构体(struct) |     Pyton Type |  字节数  |
        +----------------------------------------------------------------+
        |   x      |    pad byte              |   no value     |   1     |
        +----------------------------------------------------------------+
        |   c      |    char                  |string of length|   1     |
        +----------------------------------------------------------------+
        |   b      |    signed char           | integer        |   1     |
        +----------------------------------------------------------------+
        |   B      |    unsigned char         |  integer       |   1     |
        +----------------------------------------------------------------+
        |   ?      |    _Bool                 |   bool         |   1     |
        +----------------------------------------------------------------+
        |   h      |    short                 |  integer       |  2      |
        +----------------------------------------------------------------+
        |   H      | unsigned short           |   integer      |  2      |
        +----------------------------------------------------------------+
        |   i      |  int                     |    integer     |   4     |
        +----------------------------------------------------------------+
        |  I       |  unsigned  int           |integer or long |    4    |
        +----------------------------------------------------------------+
        |   l      |  long                    |  integer       |   4     |
        +----------------------------------------------------------------+
        |   L      |  unsigned long           |  long          |   4     |
        +----------------------------------------------------------------+
        |  q       |  long long               |   long         |   8     |
        +----------------------------------------------------------------+
        |  Q       | unsigned  long long      |    long        |  8      |
        +----------------------------------------------------------------+
        |  f       |   float                  |    float       |   4     |
        +----------------------------------------------------------------+
        |  d       |  double                  |  float         |   8     |
        +----------------------------------------------------------------+
        |   s      |   char[]                 |    string      |    1    |
        +----------------------------------------------------------------+
        |  p       |  char []                 |    string      |   1     |
        +----------------------------------------------------------------+
        |  P       |  void *                  |   long         |
        +------------------------------------------------------+

    注:
        1.q和Q只能在机器支持64位操作时有意思
        2.每个格式前可以有一个数字,表示格式  1i  表示1个int类型  4s  表示4个字符串
        3.s格式表格一定长度的字符串,4s表示长度为4的字符串,但是p表示的是pascal字符串
        4.P用来转换一个指针,其长度和机器字长有关
        5.最后一个可以用来表示指针类型的,占4字节
    为了同其他语言中的结构体交换数据,还要考虑的其他语言编译器使用了字节对齐,通常是以4个字节为单位的32位操作系统,所以struct根据本地机器字节顺序转换,可以使用格式中的第一个字符来改变对其方式：
    格式如下:
        +-------------------------------------------------------+
        | character|    byte order  |size and alignment         |
        +-------------------------------------------------------+
        |   @      |   native       |    native 凑够4个字节       |
        +-------------------------------------------------------+
        |   =      |   native       |  standard   按原字节数      |
        +-------------------------------------------------------+
        |  <       | little-endian  |  standard   按原字节数      |
        +-------------------------------------------------------+
        |  >       |   big-endian   |    standard  按原字节数     |
        +-------------------------------------------------------+
        |   ！     | network(=big-endian)| standard 按原字节数    |
        +-------------------------------------------------------+

    使用方法:
        使用方法是放在fmt的第一个位置 ：如："@5s6sif"
例:
    一个结构体:
        struct {
            unsigned short id;
            char[4] tag;
            unsigned int version;
            unsigned int count;
        }
     通过socket.recv结构到了上面的结构体数据,存在字符串s中,现在需要把它解析出来,可以使用struct的unpack()函数.
        import struct
        id,tag,version,count = struct.unpack('!H4s2I',s)
        上面的字符串中,!表示我们要使用网络字节顺序解析,因为我们的数据是从网络中接受到的,在网络上传送的时候它是网络字节顺序的，后面的H表示一个unsigned short的id,4s表示4个字节长的字符串,2I表示两个unsigned int类型的数据

        通过一个unpack,就可以把结构体里的数据保存在id,tag,version,count里了
        同样,也可以很方便的把本地数据在pakc成struct格式：
            ss = struct.pack('!H4s2I',id,tag,version,count)

        pack函数就是把id,tag,version,count 按照指定的格式转换成了结构体header,ss现在是一个字符串(类似于c结构体的字节流)
        现在就可以通过socket。send(ss)把这个字符串发送出去了
'''

import struct

a = 12.34
#将a变为二进制
bytes = struct.pack('f',a) #这个必须在转换的时候 fmt的格式要和传入对象的格式相同,否则报错
print(bytes)
#进行反转,将现有的二进制数据bytes,反转为python的数据类型
(a,) = struct.unpack('f',bytes)
#这里需要注意下,unpack返回的是tuple
#如果只有一个变量,在解析的时候需要这样:
#a, = struct.unpack('f',bytes)或(a,) = struct.unpack('f',bytes)
print(a)
'''
    如果由多个数据构成的,可以写成下面这样
    a = "hello"
    b = "world!"
    c = 2
    d = 45.123
    byes = struct.pack('5s6sif',a,b,c,d)
    此时byte就是二进制形式的数据了,可以直接写入文件比如 binfile.weitr(byes)
    当我们需要的时候可以读取出来
    bytes = binfile.read()
    在通过struct.unpack()解码成python变量
    (a,b,c,d) = struct.unpack('5s6sif')
    '5s6sif' 这个叫做fmt,就是格式化字符串,由数字加字符构成,5s表示占5个字符的字符串,i表示整数,f表示float

'''


r'''

'''