wapmorgan / binary-stream
处理二进制数据的便捷工具
Requires
- php: >=5.3.0
Requires (Dev)
- phpunit/phpunit: ~4.8.35
README
BinaryStream - 处理二进制数据的便捷工具,是 pack()/unpack() 的最佳替代品,功能丰富。
如果您正在寻找一个方便的工具,可以读取和写入二进制数据(无论是现有的还是您创建的格式),您选择正确的库。
BinaryStream - 是读取和写入二进制文件的有效工具。它支持多种高级数据类型,有时甚至让您忘记您正在处理无结构的二进制数据。
使用 BinaryStream,您可以处理网络数据包、二进制文件、系统协议和其他底层数据。
特性
- 最低支持的 PHP 版本是 5.3.0 以使用所有功能。
- 该库支持所有主要数据类型,并允许读取和写入数据。
- 支持字节序的直接顺序(大端)和反向(小端)。您可以在读取文件时在这两者之间切换。
- 支持多种尺寸的整数(8、16、32 和 64)以及罕见的(24、40、48 和 56)。
- 支持多种尺寸的小数(32 和 64)。
- 您可以读取单个字节和单个位。
- 为了方便地在文件中导航,您可以命令 BinaryStream 记住文件中的某些位置,然后再次返回。
- 支持数据组:保存配置一次,然后使用名称读取类似的数据组。
- 支持配置文件来切换文件格式和版本。
- 与标准 php 函数不同,它可以同时处理直接顺序的字节序(大端)和小端的小数。
为什么它客观上优于 pack/unpack?
- 64 位 int 的 float
- float 的字节序选择
- 罕见的,但可能 int 的大小(24、40、48、56)
- 其他特性,如数据组和配置...
PHP 5.3 就有这些。
手册
简单用法
使用 BinaryStream 最简单的方法 - 这样
use wapmorgan\BinaryStream\BinaryStream; $stream = new BinaryStream('filename.ext'); $text = $s->readString(20);
此示例读取文件开始的 20 个字节作为字符串。
一个更复杂的示例,其中数据按以下顺序排列
- 整数(int,32 位)
- 浮点数(float,32 位)
- 标志字节(其中每个位都有自己的值,8 位):第一个位确定是否在此字节之后写入其他数据,5 位为空,数据的最后 2 位为数据类型
0b00
- 在此数据之后记录 1 个字符(char,8 位)0b01
- 在此数据之后记录 10 个字符(字符串,10 字节)0b10
- 在此数据中包装在长整数(long,64 位)中的 unixtime 格式的日期时间0b11
- 目前未使用。
为了读取这些数据和依赖于标志的数据,此示例是合适的
use wapmorgan\BinaryStream\BinaryStream; $stream = new BinaryStream('filename.ext'); $int = $stream->readInteger(32); $float = $stream->readFloat(32); $flags = $stream->readBits([ 'additional_data' => 1, '_' => 5, // pointless data 'data_type' => 2, ]); if ($flags['additional_data']) { if ($flags['data_type'] == 0b00) $char = $stream->readChar(); else if ($flags['data_type'] == 0b01) $string = $stream->readString(10); else if ($flags['data_type'] == 0b10) $time = date('r', $stream->readInteger(64)); }
在此示例中,我们读取基本数据和基于标志值的基础数据。
但数据可能不会这么少。为了方便起见,您可以使用组读取函数。前面的示例可以重写如下
use wapmorgan\BinaryStream\BinaryStream; $stream = new BinaryStream('filename.ext'); $data = $stream->readGroup([ 'i:int' => 32, 'f:float' => 32, 'additional_data' => 1, '_' => 5, 'data_type' => 2, ]); if ($data['additional_data']) { if ($data['data_type'] == 0b00) $data['char'] = $stream->readChar(); else if ($data['data_type'] == 0b01) $data['string'] = $stream->readString(10); else if ($data['data_type'] == 0b10) $data['time'] = date('r', $stream->readInteger(64)); }
如果您正在读取一个包含重复数据组的文件,您可以保存一个带有名称的数据组,然后简单地引用它来读取下一个数据。让我们再介绍一个用于 data_type 的值:0b11
- 表示这是文件中的最后一个数据组。例如
use wapmorgan\BinaryStream\BinaryStream; $stream = new BinaryStream('filename.ext'); $stream->saveGroup('Data', [ 'i:int' => 32, 'f:float' => 32, 'additional_data' => 1, '_' => 5, 'data_type' => 2, ]); do { $data = $stream->readGroup('Data'); // Some operations with data } while ($data['data_type'] != 0b11);
现在,假设我们已经切换到一个与之前不同的新文件格式,它在文件开头有一个特定的标记,这将帮助区分新旧格式。例如,一个新的标签是一个字符序列 'A', 'S', 'C'
。我们需要检查标签,如果存在,则根据另一个方案解析文件,如果不存在,则使用旧版本的处理器。以下是一个示例
use wapmorgan\BinaryStream\BinaryStream; $stream = new BinaryStream('filename.ext'); if ($stream->compare(3, 'ASC')) { // parse here new format } else { $stream->saveGroup('DataOld', [ 'i:int' => 32, 'f:float' => 32, 'additional_data' => 1, '_' => 5, 'data_type' => 2, ]); do { $data = $stream->readGroup('DataOld'); // Some operations with data } while ($data['data_type'] != 0b11); }
安装
通过 composer 安装
composer require wapmorgan/binary-stream
参考
数据类型
以下表格显示了所有使用的数据类型
API
-
创建对象可以通过以下几种方式之一实现:
new BinaryStream($filename | $socket | $stream)
-
可以使用针对每种数据类型专门的方法读取数据
- 位:
-
readBit(): 布尔值
示例:
$flag = $s->readBit();
-
readBits(array $listOfBits): 布尔值和整数的数组
.示例:
$flags = $s->readBits(['a' => 2, '_' => 5, 'b' => 3]);
如果字段的长度(数组元素的值是1
,则该字段将具有true/false
,如果大于 1,则N
个连续位将组合成一个integer
。)
-
- 字符:
-
readChar(): 字符串(1)
示例:
$char = $s->readChar();
-
readChars($count): 字符串(1)的数组
示例:
$chars = $s->readChars(4);
-
- 整数
-
readInteger($sizeInBits = 32): 整数
示例:
$int = $s->readInteger(32);
它支持以下维度:8, 16, 32, 64 和 24, 40, 48, 56 位。
-
- 浮点数:
-
readFloat($sizeInBits = 32): 浮点数
示例:
$float = $s->readFloat(32);
它支持以下维度:32, 64 位。
-
- 字符串:
-
readString($length): 字符串($length)
示例:
$string = $s->readString(10);
-
- 位:
字段组
您可以使用特定名称保存字段定义的列表,并在需要读取相同块多次时使用其名称。一个组由 组配置 定义 - 字段列表、字段类型和大小。要创建组配置,请创建一个数组:键 定义字段类型和名称,值 - 它们的大小
-
键 是字段的名称,可以包含字段类型。要指定类型,请在名称前加上类型字母和冒号。类型字母
b
- 位i
- 整数f
- 浮点数c
- 字符s
- 字符串 如果未定义类型,则字段被视为位
-字段。示例:flag
-位
-字段,s:name
-字符串
-字段
-
值 是字段的大小或维度
- 如果字段具有
integer
、float
或bit
类型,则它定义了字段以位为单位的大小。 - 如果字段具有
char
或string
类型,则它定义了以字节为单位的大小。示例
'flags' => 16, // bits-field (16 bits = 2 bytes) 's:name' => 10, // string-field (80 bits = 10 bytes)
- 如果字段具有
所以完整的组配置示例
$group = [ 'flags' => 16, 'i:date' => 32, 'f:summ' => 32, 's:name' => 10, ];
导航
- 光标移动:要更改文件中的光标位置,请使用以下方法。
-
当前位置测试
isEnd(): boolean
如果光标在文件末尾,则返回 true。
-
记住文件中的位置
辅助
-
字节比较
compare($length, $bytes)
比较当前位置
$length
个字节与$bytes
。当前位置不会改变。返回 true 或 false。 -
字节序:默认情况下,
BinaryStream
以小端格式处理int
和long
。要更改字节读取顺序,请使用setEndian($endian)
方法并使用BinaryStream
常量之一
配置
高级用法。写入
如果您需要向二进制文件写入数据,则可以使用额外的方法来完成此操作。
首先,您需要以允许写入文件的模式之一打开一个文件(默认情况下,文件以只读模式打开)。为此,当您创建一个BinaryStream对象时,在第二个参数中指定以下模式之一:
正确打开文件后,您可以使用以下方法,这些方法的名字与为读取设计的方法类似。