便便代码人生

关注技术, 偶尔动动手

[原] php读取二进制流(C语言结构体struct数据文件)

Posted by bianbian on 2008-04-20 01:08

本文Tags: , , , , , , , ,

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

  1. string pack ( string $format [, mixed $args [, mixed $...]] )
  2. //Pack given arguments into binary string according to format.
  3.  
  4. array unpack ( string $format, string $data )
  5. //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 61 6E 00”,在C语言里第5个位置有终止符,name应该是“bian”;而用了unpack转换以后在php里的name却是“bian\0bian\0”。
一开始我用了strpos函数找到“\0”的位置,然后进行substr截取:

  1. $name = substr($name, 0, strpos($name, "\0"));

不过很Faint的事情发生了,不知道是strpos的bug还是substr的bug(其实测试一下就知道,懒得试),有些字符串没问题,有些字符串却只能得到空值(即$name == ”)。很是郁闷,后来找了个strtok函数,这下没有问题了:

  1. $name = strtok($name, "\0");

难为大家看了那么多,下面写个完整的php读取二进制数据流(C语言结构体struct数据)文件的示例代码:
首先是C的struct定义示例,为了演示,我就写个简单点的,实际对照上面那个$format格式表应该没有问题:

  1. struct BIANBIAN {
  2.     char name[10];
  3.     char pass[33];
  4.     int  age;
  5.     unsigned char flag;
  6. };

比如有个“bianbian.org”文件,内容就是上面的N个BIANBIAN结构体构成的。读取的php代码:

  1. //下面根据struct确定$format,注意int类型跟机器环境有关,我的32位Linux是4个长度
  2. $format = 'a10name/a33pass/iage/Cflag';
  3. //确定一个struct占用多少长度字节,如果只是读取单个结构体这是不需要的
  4. $length = 10 + 33 + 4 + 1;
  5. //也可以用fopen + fread + fclose,不过file_get_contents因为可以mmap,效率更高
  6. $data = file_get_contents('bianbian.org', 'r');
  7. for ($i = 0, $c = strlen($data); $i < $c; $i += $length) {
  8.     $bianbian = unpack("@$i/$format", $data);
  9.     //reference传递是php 5才支持的,如果用php4,得用其他办法
  10.     foreach ($bianbian as &$value) {
  11.         if (is_string($value)) {
  12.             $value = strtok($value, "\0");
  13.         }
  14.     }
  15.     print_r($bianbian);
  16. }
  17. //输出为array,即类似:
  18. Array
  19. (
  20.     [name] => 'bianbian'
  21.     [pass] => 'bianbian.org'
  22.     [age]  => 100
  23.     [flag] => 0
  24. )
  25. ...

pack应该跟unpack相反。

标签: , , , , , , , ,

遵守创作共用协议,转载请链接形式注明来自http://bianbian.org 做人要厚道

相关日志

9 Responses to “[原] php读取二进制流(C语言结构体struct数据文件)”

  1. phpbird Says:

    链接已加上。不好意思,因为你网站pr太低,我只放在了内页,请不要介意。如果您的pr升高了,我们可以做调整,谢谢。
    :)

  2. bianbian Says:

    楼上的朋友也太搞笑了。本来是您先来申请链接的,我对此类事情本来很不屑,不过看您blog也还挺可爱,就加了;按道理应该您先加我再告诉我加您才对。另外,我因为换了很多次域名,所以PR看起来低,没换前google PR是6,不知道多少才算高?呵呵

  3. Sunshow Says:

    果然很搞笑啊

  4. phpbird Says:

    误会,误会,摆了乌龙,已经发邮件给你了。
    ps:数学题比较难
    问题:为啥你回复在我发布前?

  5. 橘白婪 Says:

    好势利的友情链接哪…

  6. business daily Says:

    Problems with byte order are frustrating and I want to spare you the grief I experienced. Data is a physical concept a raw sequence of bits and bytes stored on a computer. If we store and read data one byte at a time it will work on any computer.

  7. Christina Carabini Says:

    .Because the Leptonica library is designed to work efficiently and.transparently on both big-endian and little-endian machines the.relation between the byte order and the image pixels must be handled.properly. It may also be unfamiliar to people in the image.processing community who have not tried to write efficient image.processing algorithms on binary packed images for both endian.architectures..All hardware allows byte addressing.

  8. Tin tức CNTT,Tin tuc,CNTT,Điện thoại,Dien thoai,Mobile,Thảo luậnThao luan,Chia sẻ kinh nghiệm,Chia se kinh nghiem,Chia se,Kinh nghiem,Thủ thuật,Thu thuat,Ngôn ngữ ,Ngon ngu,Lập trình,Lap trinh,Ngôn ngữ lập trình,Visual,Java, Says:

    Tin tức CNTT,Tin tuc,CNTT,Điện thoại,Dien thoai,Mobile,Thảo luậnThao luan,Chia sẻ kinh nghiệm,Chia se kinh nghiem,Chia se,Kinh nghiem,Thủ thuật,Thu thuat,Ngôn ngữ ,Ngon ngu,Lập trình,Lap trinh,Ngôn ngữ lập trình,Visual,Java,Lap trinh web,Lập trình we…

    [...]» [原] php读取二进制流(C语言结构体struct数据文件) » » 便便代码人生[...]…

  9. hosting 1 Says:

    hosting 1…

    [...]» [原] php读取二进制流(C语言结构体struct数据文件) » » 便便代码人生[...]…

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>