尽管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 61
6E
00”,在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 TEST{ 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; }
转自:http://bianbian.org http://www.zbl110119.cn/archives/130/comment-page-1
相关推荐
在PHP中,虽然不直接支持C语言的结构体(struct),但是通过`pack`和`unpack`函数,我们可以实现对二进制数据流的处理,从而读取和操作类似于C语言结构体的数据文件。这两个函数允许我们将数据从PHP的内部表示转换为...
在计算机科学领域,二进制文件是指存储在磁盘上的一系列未经解释的二进制数据。这些数据通常不能直接被人阅读理解,而是由特定的应用程序进行解析。常见的二进制文件包括图像文件(如PNG、JPEG、BMP)、音频文件(如...
`.dat`文件本身并没有特定的格式,它只是一个二进制或文本文件,可以按照开发者的需求来组织数据。下面我们将深入探讨如何在C语言中处理这种文件类型,以及在操作过程中需要注意的关键点。 ### 1. 打开文件 在...
一旦文件被成功打开,我们就可以使用`fread()`函数来读取二进制数据。`fread()`函数接受四个参数:目标缓冲区,每个元素的大小,元素的数量以及要读取的文件指针。例如,如果你知道文件包含整型数据,你可以这样做:...
假设我们已经有一个包含学生信息的二进制文件,我们需要打开文件,然后逐个读取结构体实例。以下是如何实现这个功能的一个示例: ```c // 打开文件 FILE* file = fopen("students.bin", "rb"); // 读取结构体 ...
- **文件读取**:使用`fread`函数从二进制文件中读取数据到结构体数组。 - **遍历结构体数组**:再次使用`for`循环来遍历结构体数组并显示信息。 - **计算平均值**:累积所有年龄值后除以总人数得到平均年龄。 ### ...
4. 存储数据:将读取到的三角形信息存储到结构体数组或自定义的数据结构中,如`struct Triangle { Vector3 normal; Vertex3 vertices[3]; }`。 5. 显示:使用OpenGL或其他图形库将这些三角形绘制出来。需要计算每个...
该程序是用于处理二进制文件的C语言代码,主要功能包括读取二进制文件中的学生记录,统计最高分和平均分,并将相关信息写入文本文件。以下是程序中的关键知识点: 1. **二进制文件操作**:程序通过`fopen()`函数以...
- 读取Socket输入流(`InputStream`)中的数据,反序列化为结构体对象。 - 处理数据,然后将结果序列化并写入Socket输出流(`OutputStream`)。 2. 创建客户端(Java程序模拟): - 创建`Socket`连接到服务器端...
用于二进制文件,我们通常使用"wb"(写入二进制)或"rb"(读取二进制)模式。 2. `fclose()`: 关闭文件,释放资源。使用完文件后,必须调用此函数关闭文件指针。 3. `fwrite()`: 将内存中的数据写入文件。需要指定要...
总的来说,用C语言读取汉字库文件是一项涉及文件I/O、二进制数据解析和内存管理的复杂任务。理解和处理.FON文件需要深入理解文件格式,同时遵循良好的编程实践以避免潜在的问题,如内存泄漏和错误处理。在实际项目中...
2. **读取二进制数据**:使用Java的DataInputStream或者自定义的BufferedReader从socket的输入流中读取数据。对于UDP通信,可以使用DatagramPacket的getData()方法获取数据。 3. **解析数据**:根据结构体的布局,...
本主题关注的是如何使用C语言通过结构体和FILE指针来读取并输出二进制图像文件的信息。 首先,了解C语言中的结构体是关键。结构体允许我们将相关的数据项组合在一起,形成一个新的数据类型。在处理图像时,我们可以...
`fread`和`fwrite`分别用于读取和写入二进制文件,而`fgets`和`fprintf`则适用于ASCII文本文件。 4. **ASCII与二进制转换**:ASCII格式是可读的文本形式,每个字符对应一个7位或8位的二进制数字。将MRI数据从ASCII...
可以使用`fopen()`打开文件,`fread()`读取二进制数据,`fclose()`关闭文件。在读取wav文件时,我们需要先读取头文件的部分,解析出必要的信息,然后跳过头文件,直接读取数据部分。 3. **解析wav头文件**: 在...
从给定的文件信息来看,主要涉及的主题是C语言编程中的文件处理,特别是对数据流和二进制流的理解,以及这些概念在智能家居现代建设中的潜在应用。下面将详细解析这些知识点。 ### C语言中的文件处理 #### 文件的...
读取时,再将二进制文件的内容还原为结构体数组。这种存储方式的优点在于速度快、占用空间小,但需要注意文件格式的兼容性和数据的正确性。 此外,内存管理是C语言中的关键环节。内存整理功能可能涉及到动态内存...
本示例“file_to_struct.rar_结构体”探讨了如何将结构体存储到文件中,然后从文件中读取,这是在进行数据持久化或跨程序传递数据时常见的操作。下面我们将深入探讨这一主题。 1. **结构体定义**: 在C语言中,...
二进制文件与文本文件不同,它不依赖于特定的字符编码,而是直接以字节流的形式存储数据,因此能更精确地保存和恢复原始数据。 `fread()` 和 `fwrite()` 是C语言标准库中的两个关键函数,用于二进制文件的读写操作...