php读取二进制流(C语言结构体struct数据文件)的深入解析


Posted in PHP onJune 13, 2013

尽管php是用C语言开发的,不过令我不解的是php没有提供对结构体struct的直接支持。
不过php提供了pack和unpack函数,用来进行二进制数据(binary data)和php内部数据的互转:

string pack ( string $format [, mixed $args [, mixed $...]] )  
 //Pack given arguments into binary string according to format.  
array unpack ( string $format, string $data )  
//Unpacks from a binary string into an array according to the given format.

其中,$format跟perl里的pack格式类似,有如下一些(中文是我加的,有不准确的欢迎提出):
a NUL-padded string,即“\0”作为“空字符”的表示形式
A SPACE-padded string,空格作为“空字符”的表示形式
h Hex string, low nibble first,升序位顺序
H Hex string, high nibble first,降序位顺序
c signed char,有符号单字节
C unsigned char,无符号单字节
s signed short (always 16 bit, machine byte order)
S unsigned short (always 16 bit, machine byte order)
n unsigned short (always 16 bit, big endian byte order)
v unsigned short (always 16 bit, little endian byte order)
i signed integer (machine dependent size and byte order)
I unsigned integer (machine dependent size and byte order)
l signed long (always 32 bit, machine byte order)
L unsigned long (always 32 bit, machine byte order)
N unsigned long (always 32 bit, big endian byte order)
V unsigned long (always 32 bit, little endian byte order)
f float (machine dependent size and representation)
d double (machine dependent size and representation)
x NUL byte,实际使用的时候作为跳过多少字节用,很有用
X Back up one byte,后退1字节
@ NUL-fill to absolute position,实际使用的时候作为从开头跳到某字节用,很有用
实际使用发现:C里的“\0”(即字符串终止符)在php里并不是终止符,而是作为了字符串的一部分。因此,必须对“\0”进行特殊处理,才能进行struct和php内部数据的完美互转。比如 char name[10]; 如果实际数据是“62 69 61 6E 00 62 69 616E00”,在C语言里第5个位置有终止符,name应该是“bian”;而用了unpack转换以后在php里的name却是“bian\0bian\0”。
一开始我用了strpos函数找到“\0”的位置,然后进行substr截取.

不过很Faint的事情发生了,不知道是strpos的bug还是substr的bug(其实测试一下就知道,懒得试),有些字符串没问题,有些字符串却只能得到空值(即$name == ”)。很是郁闷,后来找了个strtok函数,这下没有问题了.
难为大家看了那么多,下面写个完整的php读取二进制数据流(C语言结构体struct数据)文件的示例代码:
首先是C的struct定义示例,为了演示,我就写个简单点的,实际对照上面那个$format格式表应该没有问题:

struct BIANBIAN {  
    char name[10];  
    char pass[33];  
    int  age;  
    unsigned char flag;  
};

比如有个“file.dat”文件,内容就是上面的N个BIANBIAN结构体构成的。读取的php代码:
    <?php  
     //下面根据struct确定$format,注意int类型跟机器环境有关,我的32位Linux是4个长度  
     $format = 'a10name/a33pass/iage/Cflag';  
     //确定一个struct占用多少长度字节,如果只是读取单个结构体这是不需要的  
     $length = 10 + 33 + 4 + 1;  
     //也可以用fopen + fread + fclose,不过file_get_contents因为可以mmap,效率更高  
     $data = file_get_contents('file.dat', 'r');  
     for ($i = 0, $c = strlen($data); $i < $c; $i += $length) {  
         $bianbian = unpack("$format", $data);  
         //reference传递是php 5才支持的,如果用php4,得用其他办法  
         foreach ($bianbian as &$value) {  
             if (is_string($value)) {  
                 $value = strtok($value, "\0");  
             }  
         }  
         print_r($bianbian);  
     }  
    ?> 

pack应该跟unpack相反。
顺便附上生成结构体文件的C语言代码:
    #include <stdio.h>  
    #include <string.h>      struct example       
    {      
        char name[10];  
        char pass[33];  
        int  age;  
        unsigned char flag;  
    };  
    int main()     
    {  
        example test;  
        example read;     
        FILE *fp;  
        test.age = 111;     
        test.flag = 10;  
        strcpy(test.name, "Hello World!");  
        strcpy(test.pass, "zbl110119");  
        fp = fopen("file.dat", "w+");  
        if (!fp)  
        {  
            printf("open file error!");  
            return -1;  
        }  
        rewind(fp);  
        fwrite(&test, sizeof(example), 1, fp);  
        rewind(fp);  
        fread(&read, sizeof(example), 1, fp);  
        printf("%d, %s\n", read.age, read.name);  
        fclose(fp);  
        return 0;  
    } 

PHP 相关文章推荐
如何隐藏你的.php文件
Jan 04 PHP
php 生成WML页面方法详解
Aug 09 PHP
php下统计用户在线时间的一种尝试
Aug 26 PHP
用PHP实现 上一篇、下一篇的代码
Sep 29 PHP
Session服务器配置指南与使用经验的深入解析
Jun 17 PHP
PHP json_encode中文乱码问题的解决办法
Sep 09 PHP
php表单请求获得数据求和示例
May 15 PHP
PHP扩展程序实现守护进程
Apr 16 PHP
实现PHP框架系列文章(6)mysql数据库方法
Mar 04 PHP
Yii2超好用的日期和时间组件(值得收藏)
May 05 PHP
Yii列表定义与使用分页方法小结(3种方法)
Jul 15 PHP
PHP读取XML格式文件的方法总结
Feb 27 PHP
基于PHP Socket配置以及实例的详细介绍
Jun 13 #PHP
深入php socket的讲解与实例分析
Jun 13 #PHP
PHP数据类型的总结分析
Jun 13 #PHP
如何用C语言编写PHP扩展的详解
Jun 13 #PHP
探讨:如何编写PHP扩展
Jun 13 #PHP
PHP APC的安装与使用详解
Jun 13 #PHP
eAccelerator的安装与使用详解
Jun 13 #PHP
You might like
php数组中包含中文的排序方法
2014/06/03 PHP
phpstorm编辑器乱码问题解决
2014/12/01 PHP
php封装的验证码类分享
2017/02/26 PHP
YII框架中使用memcache的方法详解
2017/08/02 PHP
PHP大文件分割上传 PHP分片上传
2017/08/28 PHP
PHP多进程之pcntl_fork的实例详解
2017/10/15 PHP
微信公众平台开发教程①获取用户Openid及个人信息图文详解
2019/04/10 PHP
禁止直接访问php文件代码分享
2020/05/05 PHP
兼容ie和firefox js关闭代码
2008/12/11 Javascript
extjs grid取到数据而不显示的解决
2008/12/29 Javascript
Jquery 自定义动画概述及示例
2013/03/29 Javascript
浅析JavaScript基本类型与引用类型
2014/05/28 Javascript
jQuery实现鼠标悬停显示提示信息窗口的方法
2015/04/30 Javascript
JavaScript中操作字符串之localeCompare()方法的使用
2015/06/06 Javascript
JavaScript记录光标在编辑器中位置的实现方法
2016/04/22 Javascript
AngularJS 简单应用实例
2016/07/28 Javascript
整理关于Bootstrap过渡动画的慕课笔记
2017/03/29 Javascript
小程序实现发表评论功能
2018/07/06 Javascript
基于AngularJs select绑定数字类型的问题
2018/10/08 Javascript
解决 window.onload 被覆盖的问题方法
2020/01/14 Javascript
详解Vue之事件处理
2020/07/10 Javascript
Javascript柯里化实现原理及作用解析
2020/10/22 Javascript
Python计算三维矢量幅度的方法
2015/06/15 Python
深入分析python数据挖掘 Json结构分析
2018/04/21 Python
python切片及sys.argv[]用法详解
2018/05/25 Python
python+influxdb+shell编写区域网络状况表
2018/07/27 Python
pycharm创建一个python包方法图解
2019/04/10 Python
python默认参数调用方法解析
2020/02/09 Python
Melijoe英国官网:法国儿童时尚网站
2016/11/18 全球购物
台湾网友喜爱的综合型网路购物商城:Yahoo! 奇摩购物中心
2018/03/10 全球购物
自学考试自我鉴定范文
2013/09/26 职场文书
总经理职责范文
2013/11/08 职场文书
面试后的感谢信范文
2014/02/01 职场文书
实习生评语
2014/04/26 职场文书
优秀党务工作者事迹材料
2014/05/07 职场文书
面试必备的求职信
2014/05/25 职场文书