用c++寫文件複製,以二進位將任意文件讀入,再以二進位寫入另一個文件,為什麼會出錯?

【問題已解決】

實際上使用文本文件,png圖片文件,甚至exe文件測試都是沒有問題的,但是對於word文件出現了問題,提示「文件被破壞」,但是恢復文件內容又完全正確。

請問可能是哪裡出現問題?

ps:其實我是想做一個簡單的文件加密程序,對二進位內容稍作修改使文件無法打開。原樣讀入輸出實現複製是第一步實驗,結果遇到了這個問題。

(原來有錯的)核心代碼如下:

fstream fout(szDestFile, ios::out |ios::binary );

fstream fin(szOrigFile, ios::in |ios::binary);

while(!fin.eof())

{

char szBuf[256] = {0};

fin.read(szBuf, sizeof(char) * 256);

if (fout.bad())

{

bRet = false;

break;

}

//

fout.write(szBuf, sizeof(char) * 256);

}

}

錯誤如 @比目魚 的答案所說,文件末尾寫入了多餘的位元組,影響了文件驗證;另外fin.eof()只有在讀入失敗後才會變true,也會導致多寫一次。改正為:

while(!fin.eof())

{

char szBuf;

fin.read(szBuf, sizeof(char));

if(fin.eof()) break;

if (fout.bad())

{

bRet = false;

break;

}

fout.write(szBuf, sizeof(char));

}

就沒問題了。測試可以複製word文檔。


我覺得多半是你沒開b模式,導致庫在寫入的時候把所有的0x0A都輸出成了兩個字元0x0D 0x0A

也就是所謂的
變成


用md5或者shasum等命令行工具檢查一下src和dst的hash是否相同,不同則說明兩個文件內容不同,同時把代碼貼上來。另外懷疑題主使用了std::fstream以類似如下的方式複製文件:

// fin, fout是std::fstream的實例

char ch;

while(!fin.eof()) {

fin.read(ch, sizeof(ch));

fout.write(ch, sizeof(ch));

}

(以前一個學妹做c++作業時就這麼寫過)這種方式會在目標文件尾寫入源文件末位元組兩次(讀完最後一個位元組時fin.eof()仍為true,fout.write多執行一次)。

對於純文本文件,目標文件尾多一個位元組不影響文本編輯器正常顯示;對於.exe這種PE格式的可執行文件,其文件頭之後是節表(section table),記錄了其後每個section的長度和偏移量等信息,文件尾多出一個位元組並不影響PE loader正確載入該可執行文件(已測試);對於.png,其文件頭之後是一堆數據塊,每個數據塊的頭部仍然存有塊大小等信息,文件尾多出一個位元組也不會影響該圖像的正常顯示(已測試)。

然而對於msoffice的.docx,.pptx等文件(實際上是zip壓縮文件),若文件尾多出一個位元組,相關程序在載入這樣的文件時可能會因為驗證文件完整性失敗而報錯「文件損壞」。然而這些文件內部仍有存儲長度和偏移量等信息的機制,所以在點擊「恢復文檔」之後仍可被正確地解壓縮並顯示。


用beyondcompare之類的軟體對比一下兩個文件的二進位,是否完全一致


因為寫多了。

這段代碼輸出的文件大小只能是256的整數倍,很可能和原文件不符。刪掉輸出文件末尾多出的0x00,應該就可以了。


因為word文件有些情況下你可以破壞一小部分文件內容……


這麼改效率也太低了吧,確定一個位元組一個位元組讀?

那個read.函數我記得不錯的話會返回讀進去的位元組數的,寫的時候要按照read函數返回的位元組數去寫,而不是按照buffer大小去寫。

也就是說,要拿到實際讀取的位元組數,寫的時候只寫入實際讀取的位元組數,不能寫多了。

read函數給進去的長度是最大讀取長度,實際可能不會讀那麼多數據出來,比如遇到了文件尾。


推薦閱讀:

PPT圖表有哪些設計和美化方法?下面這種PPT圖表是如何製作的?
關於計算機二級office的學習與備考?
藏文用word文檔排版的問題?
想系統的學習愛word,excel,ppt, 有什麼書或視頻推薦?
為什麼Office 365不提供離線安裝包?

TAG:編程 | MicrosoftOffice | CC | Windows文件管理 |