PHP实现将2字节数据存入单个数组元素的方法咨询
嘿,这个需求我熟!完全可以搞定,而且确实需要用循环来成对处理字节——毕竟你得把每两个8位字节捏成一个16位值,之后还要修改位,最后要是需要存回文件的话还得拆回去。我给你一步步讲清楚,再附上代码示例:
核心注意点
首先得明确:WAV的16位音频数据大多是**小端序(Little-Endian)**的,也就是低字节在前、高字节在后,合并的时候别搞反了,不然数值会完全错掉!
具体实现步骤
- 读取WAV文件数据
小文件直接用file_get_contents读整个文件就行,大文件的话建议用fopen+fread逐块读,避免内存爆炸。 - 循环成对处理字节
循环步长设为2,每次取两个字节,按小端序合并成16位整数:比如第一个字节是低8位,第二个是高8位,计算方式是$16bitVal = ($byte2 << 8) | $byte1;。 - 修改16位值的最后一位
这里的“最后一位”就是二进制的最低位(第0位):- 要改成0:
$modifiedVal = $16bitVal & 0xFFFE;(用掩码把最后一位清零) - 要改成1:
$modifiedVal = $16bitVal | 0x0001;(用或运算把最后一位设为1)
- 要改成0:
- (可选)存回WAV文件
把修改后的16位值拆回两个字节,按原字节序拼回去,再写入文件就行。如果只需要数组的话,这步可以跳过。
完整代码示例(小文件版)
<?php $wavFile = 'rock.wav'; $rawData = file_get_contents($wavFile); $totalBytes = strlen($rawData); $sixteenBitArray = []; $modifiedData = ''; // 注意:WAV文件头通常是44字节,如果只想处理音频数据,从索引44开始循环 $startAt = 0; // 改成44跳过文件头 for ($i = $startAt; $i < $totalBytes; $i += 2) { // 防止最后剩下单个字节,直接跳过 if ($i + 1 >= $totalBytes) break; // 取出两个字节并转成整数 $lowByte = ord($rawData[$i]); $highByte = ord($rawData[$i + 1]); // 小端序合并成16位值 $current16Bit = ($highByte << 8) | $lowByte; $sixteenBitArray[] = $current16Bit; // 修改最后一位为1(你可以换成0或者自定义逻辑) $modified16Bit = $current16Bit | 0x0001; // 拆回两个字节,拼回二进制数据 $newLowByte = $modified16Bit & 0xFF; $newHighByte = ($modified16Bit >> 8) & 0xFF; $modifiedData .= chr($newLowByte) . chr($newHighByte); } // 如果跳过了文件头,要把原头加回去 if ($startAt > 0) { $modifiedData = substr($rawData, 0, $startAt) . $modifiedData; } // 保存修改后的文件(可选) file_put_contents('modified_rock.wav', $modifiedData); // 输出处理后的16位数组 print_r($sixteenBitArray); ?>
大文件优化版
如果你的WAV文件特别大,用上面的方法会占很多内存,换成逐字节读取的方式更高效:
<?php $inputPath = 'rock.wav'; $outputPath = 'modified_rock.wav'; // 打开文件流 $inStream = fopen($inputPath, 'rb'); $outStream = fopen($outputPath, 'wb'); // 先复制44字节的WAV文件头 fwrite($outStream, fread($inStream, 44)); // 循环读取每2字节处理 while (!feof($inStream)) { $bytes = fread($inStream, 2); // 不足2字节就退出循环 if (strlen($bytes) < 2) break; $lowByte = ord($bytes[0]); $highByte = ord($bytes[1]); $current16Bit = ($highByte << 8) | $lowByte; // 修改最后一位 $modified16Bit = $current16Bit | 0x0001; // 拆回字节并写入输出文件 $newLow = $modified16Bit & 0xFF; $newHigh = ($modified16Bit >> 8) & 0xFF; fwrite($outStream, chr($newLow) . chr($newHigh)); } // 关闭流 fclose($inStream); fclose($outStream); ?>
这样处理大文件的时候,内存占用会非常低,不会卡顿~
内容的提问来源于stack exchange,提问作者hizz
相关产品推荐
相关产品推荐

