pack — 將數(shù)據(jù)打包成二進(jìn)制字符串
總是無(wú)法把這個(gè)函數(shù)的用法跟它的函數(shù)說(shuō)明聯(lián)系起來(lái),我都有點(diǎn)懷疑是不是描述錯(cuò)了。
首先要了解二進(jìn)制字符串,才能比較好理解這個(gè)函數(shù):
二進(jìn)制字符串
字面上理解『二進(jìn)制字符串』應(yīng)該是像 01010101這樣的東西,我以前一直也是這樣理解的,直到遇到了 pack()函數(shù),讓我有點(diǎn)懷疑人生。
我們其實(shí)是沒(méi)辦法直接看到二進(jìn)制碼的,我們?cè)谄聊簧峡吹降乃?,其?shí)都是二進(jìn)制碼的表現(xiàn)形式,也就是這里說(shuō)的二進(jìn)制字符串。什么意思呢?
/**
* 我們看到的 a 是一個(gè)字符串,它就是一個(gè)二進(jìn)制字符串
* a 是二進(jìn)制碼 01100001 的表現(xiàn)形式
*/
$str = 'a';
/**
* n 無(wú)符號(hào)短整型(16位,大端字節(jié)序)
* 把 97 當(dāng)成 16位無(wú)符號(hào)短整型 存入2個(gè)字節(jié)大小的二進(jìn)制碼里,表現(xiàn)為 a
*/
$bin_str = pack('n', 97);
echo '|', $bin_str, "\n"; // 輸出: | a
echo strlen($bin_str); // 輸出 2, 變量$bin_str 占兩個(gè)字節(jié)
模擬 pack() 函數(shù)進(jìn)行數(shù)據(jù)打包
$int = 97;
$int = 299;
$int = 65579;
$r1 = packShortIntTo2bytes($int);
$r2 = pack('n', $int);
printf("r1 = |%s\n", $r1);
printf("r2 = |%s\n", $r2);
printf("r2 len: %d\n", strlen($r1));
printf("r2 len: %d\n", strlen($r2));
/**
* 將16位短整型打包成2字節(jié)的二進(jìn)制字符串
*
* 這里直接利用php函數(shù)的便利寫的, 還是可以有其他的實(shí)現(xiàn)方式
* 最直接的實(shí)現(xiàn)方式步驟:
* 1.先將整數(shù)轉(zhuǎn)成二進(jìn)制字符的表現(xiàn)形式: 001010101
* 2.再將二進(jìn)制字符補(bǔ)足8的倍數(shù), 如果從低位解析就不用
* 3.取出每8位一個(gè)字節(jié)的二進(jìn)制字符, 將其轉(zhuǎn)為整型: bindec()
* 4.用 chr() 函數(shù)將整數(shù)轉(zhuǎn)成 ascii 所對(duì)應(yīng)的字符
* 5.將字符拼接起來(lái)
* 還沒(méi)有試過(guò), 理論上也是可行的
*
* @param int $int
* @return bool|string
*/
function packShortIntTo2bytes(int $int) {
if ($int > 65536) {
$int = $int % 65536;
}
# 先轉(zhuǎn)成 16 進(jìn)制
$hex = dechex($int);
# 確保是 4 位的16進(jìn)制, 16位的二進(jìn)制可以用4位十六進(jìn)制表示
if (strlen($hex) < 4) {
$hex = str_pad($hex, 4, '0', STR_PAD_LEFT);
}
# 最后將十六進(jìn)制字符串轉(zhuǎn)成二進(jìn)制字符串
return hex2bin($hex);
}
將數(shù)據(jù)打包成二進(jìn)制字符串的作用
打包數(shù)據(jù),就是壓縮數(shù)據(jù)。
我們將一個(gè)整型 9999 存入一個(gè)文件里面,就是一個(gè)占用 4 字節(jié)的字符串。
但如果把 9999 打包成16位的無(wú)符號(hào)短整型,就只是占用2個(gè)字節(jié),16位的無(wú)符號(hào)短整型可以表示 0 ~ 65536 的整數(shù)。