前言
好久没写技术文章了,忙于毕业、工作。。。。(好吧实际上我就是懒)。我已经尽力(至少天天念着)在拓宽、挖深自己的技术栈了,但是效果真心不咋滴。
pack和unpack在PHP技术栈里应该算是非常冷门的函数了。因为,大部分的PHPer只会在无尽的业务中挣扎,二进制这种东西.......
咳咳咳,首先你得知道“文本文件”和“二进制文件”的区别,然后就可以搞事情了。
搞什么事情?比如在TCP基础上弄个应用层网络协议啊,进程间通信的二进制传输啊之类的,反正多学点总不会错嘛。
手册嘛,看看就好。做一个简单示例:
- 把c语言的一个结构体存储到一个二进制文件中。
- 然后PHP读取二进制文件,解析这个结构体。
- 用PHP按照结构体的格式,再把解析出来的数据,存储到另一个二进制文件中。
第一步 C语言:封印
1、先声明结构体
这个没啥好说的,基本的结构体声明。
#include <stdio.h>
#include <string.h>
struct student
{
int Id;
char name[20];
};
2、定义结构体
咳咳咳,对于不经常写C的phper来说明一下,我注释中的坑1。
C语言main函数里声明的字符数组,未初始化乱码问题。这里有篇博客讲的很清楚了(我就是懒,所以自己看):blog.csdn.net/weixin_3848…
当然,我建议你把这一行代码去掉,走一遍整篇文章的流程。会有惊喜哟~~
int main(int argc, char *argv[])
{
struct student st;
st.Id = 123;
memset(st.name, '\0', sizeof(st.name)); // 坑1
strcpy(st.name, "klus");
}
3、存储结构体为二进制文件
int main(int argc, char *argv[])
{
struct student st;
st.Id = 123;
memset(st.name, '\0', sizeof(st.name));
strcpy(st.name, "klus");
FILE *p = fopen("a.dat", "wb");
if (p == NULL)
{
return 0;
}
fwrite(&st, sizeof(struct student), 1, p);
fclose(p);
return 0;
}
编译,链接,运行。duang~~~
一个活生生的a.dat文件就这么生成了。
第二步 PHP:解封
1、读文件
$str = file_get_contents("a.dat");
只有一行代码?是的,就是这么简单......
2、解析
$str = file_get_contents("a.dat");
$result = unpack("lId/a*name", $str);
var_dump($result);
多了两行,哈哈哈。运行以后的结果就是:

1)Id字段解析
这里稍微说明一下,lId/a*name里面的l表示有符号的32位整型主机字节序来解析。
与之类似的还s表示有符号的16位整型主机字节序。
试着改一下,改成sId/a*name,效果如下图所示:

klus变成了22个字节,惊不惊喜!意不意外!?至于为啥会这样,自己想......
2)name字段解析
再说说a*解析成的name字段,这个*有点意思,你可以换成数字试试。a就表示NUL 填充的字符串。当你把解析格式换成lId/A*name时,结果就是下图了:

来一段引用,官方:
Changes were made to bring this function into line with Perl:
The "a" code now retains trailing NULL bytes.
The "A" code now strips all trailing ASCII whitespace (spaces, tabs, newlines, carriage returns, and NULL bytes).
The "Z" code was added for NULL-padded strings, and removes trailing NULL bytes.
菜鸟的翻译如下:
自 PHP 5.5.0 起,为 Perl 兼容进行了下列更改:
"a" 代码保留尾随 NULL 字节。
"A" 代码删除所有尾随 ASCII 空白。
新增 "Z" 代码用于 NUL 填充的字符串,并移除尾随 NULL 字节。
如果你把前面的坑1的代码去掉,你就能明显感觉到这三者之间的差别了!
第三步 PHP:封印
$str = file_get_contents("a.dat");
$result = unpack("lId/a*name", $str);
$outp = pack("la20", $result["Id"], $result["name"]);
file_put_contents("b.dat", $outp);
懒得写了,读者要是有兴趣,就自己试着换成别的字符,比如吧20换成30之类的。
总结
反正,多做多想多踩坑,一路踩过来就完事儿了。
要是写得不对,欢迎各位大佬指正~~