我開啟了一個檔案(二進位)的,然後利用bin2hex函數,將其變成了十六進位的字串,並且修改了其中一個特定位置的數值,現在問題是,我想儲存回去,發現變成了ASCII檔案,請問各位,如何應該儲存成和源檔案格式一樣的代碼呢?
下面是代碼:
$fp=fopen("sample.bin",'rb');
$word='';
while(!feof($fp)){
$buf = bin2hex(fread($fp,48));
$pos = strpos($buf, '02000100'); // 尋找土地
//if $pos == 0 {
// echo "這是土地";
//}
echo $buf;
echo "\n-------------\n";
echo ($pos/2);
echo $buf2=str_replace("02000100","BE010000",$buf);
$word=$word.$buf2;
echo "\n";
}
fclose($fp);
echo $word;
$new= fopen('new.bin','w');
fwrite($new,$word);
fclose($new);
?>
回複討論(解決方案)
一個檔案一種格式,存兩種格式也沒有意義,可以在需要時候再取出來轉換,不用轉為十六進位
1、既然你用 $fp=fopen("sample.bin",' rb'); 開啟檔案,表示你的程式可在 window 系統下工作,那麼寫入時也應 $new= fopen('new.bin','w b');
b 表示二進位方式,window 下必須嚴格區別,linux 下無所謂
2、處理後的 $word 的內容是十六進位表示,你在寫入檔案時並沒有再轉回二進位
可用 $word = pack('H*', $word); 轉換
$word = '';
$from = pack('H*', '02000100');
$target = pack('H*', 'BE010000');
while(!feof($fp)){
$buf = bin2hex(fread($fp,48));
$buf2 = str_replace($from, $target, $buf);
$word .= $buf2;
}
這樣 $word 中依舊是位元據
$word = '';
$from = pack('H*', '02000100');
$target = pack('H*', 'BE010000');
while(!feof($fp)){
$buf = bin2hex(fread($fp,48));
$buf2 = str_replace($from, $target, $buf);
$word .= $buf2;
……
謝謝xuzuning的意見,我按照你的修改了代碼,如下:
$fp=fopen("old.bin",'rb');
$word='';
$from = pack('H*', '02000100');
$target = pack('H*', 'BE010000');
while(!feof($fp)){
$buf = bin2hex(fread($fp,48));
$buf2 = str_replace($from, $target, $buf);
$pos = strpos($buf, '02000100'); // 尋找土地
//if $pos == 0 {
// echo "這是土地";
//}
echo $buf;
echo "\n-------------\n";
echo ($pos/2);
echo $buf2;
//echo $buf2=str_replace("02000100","BE010000",$buf);
$word=$word.$buf2;
echo "\n";
}
fclose($fp);
//echo $word;
$new= fopen('new.bin','wb');
fwrite($new,$word);
fclose($new);
?>
但是產生的new.bin的大小依然是old.bin的兩倍,和之前沒有什麼區別,我的測試環境是在我的WIN2008的伺服器上,IIS7+PHP,您還有什麼建議嗎?
對不起,我 #3 的代碼錯了,應該是這樣
$word = '';
$from = pack('H*', '02000100');
$target = pack('H*', 'BE010000');
while(!feof($fp)){
$buf = fread($fp,48);
$buf2 = str_replace($from, $target, $buf);
$word .= $buf2;
}
完全按二進位方式操作
對不起,我 #3 的代碼錯了,應該是這樣
$word = '';
$from = pack('H*', '02000100');
$target = pack('H*', 'BE010000');
while(!feof($fp)){
$buf = fread($fp,48);
$buf2 = str_replace($from, $target, $buf);
$wo……
感謝,問題解決!
嘮叨說了關鍵了, windows的確區分文本和二進位檔案, 因為文本的末尾是以某個特殊位元組標示的.
WINDOWS下,不太瞭解的同學經常用fgetc函數以文本開啟二進位檔案, 試圖一個位元組一個位元組的讀取, 結果發現只能讀了一半就開始返回EOF了, 其實是因為恰好某個位元組是文本裡的作為結束符的特殊位元組。
但Linux一律以系統API : read返回0作為檔案末,所以b參數是被忽略的。
樓主的作法多餘了, 不就是想找到 土地 兩個字, 然後替換一下嗎 ?
不知道樓主所說的二進位檔案是怎麼產生的, 其實一切都是二進位, 只是在windows下b開啟和非b開啟得到的結果會有區別, 非b開啟和用文字編輯器編輯結果是一致的.
假設你原本的檔案就是一個utf8文字檔,裡面有“土地”兩個字,作法很簡單,UTF8多位元組編碼的,迴圈fread並不一定正好能將完整的“土地”兩個字的位元組讀到一個buffer裡,所以比較好的辦法是file_get_contents,之後直接str_replace("土地", “兄弟”)即, 在C語言裡其實就是記憶體映射後替換字串.
轉什麼十六進位, 純屬多此一舉, 而且迴圈讀是一定有bug的, 可能"土地"兩個字是被拆開讀進來的.
就連vim這種軟體都是記憶體映射的, 檔案太大它也沒辦法, 只能告訴你失敗.
請問怎麼可以調用儲存視窗儲存麼