2010-11-16 241 views
0

我是C++的新手,我必須爲學校做一項任務。C++ ifstream/fstream損壞數據

我需要在不使用api調用或系統集成命令的情況下複製二進制*文件。在學校我們使用Windows機器。

我四處搜尋了一下,我發現,不使用任何API的是使用的iostream(ifstream的/ fstream的) 下面是我使用的代碼複製數據的最佳方式:

int Open(string Name){ 

    int length; 
    char * buffer; 
    ifstream is; 
    fstream out; 
    FILE* pFile; 
    is.open (Name.c_str(), ios::binary); 

    // get length of file: 
    is.seekg (0, ios::end); 
    length = is.tellg(); 
    is.seekg (0, ios::beg); 

    // allocate memory: 
    buffer = new char [length]; 

    // read data as a block: 
    is.read (buffer,length); 
    is.close(); 

    pFile = fopen ("out.exe" , "w"); 
    fclose(pFile); 

    out.open("out.exe", ios::binary); 

    out.write(buffer, length); 

    out.close(); 

    delete[] buffer; 
    return 0; 
} 

out.exe心不是正常工作,並在winhex.exe 看着它後,我看到數據已經modefied,而我沒有做任何事的

誰能幫助我?

*文件是一個簡單的Hello World程序,它提示消息框的 「Hello World」

編輯:

對不起,我的反應遲鈍,它正在睡覺。 不管怎樣,我已經在十六進制編輯器中打開了兩個(結果和原始)程序。 似乎一切我嘗試這條線:

Offset  0 1 2 3 4 5 6 7 8 9 A B C D E F 

00000200 4C 00 00 00 00 30 00 00 00 02 00 00 00 0D 0A 00 L 0  

變成這樣:

Offset  0 1 2 3 4 5 6 7 8 9 A B C D E F 

00000200 4C 00 00 00 00 30 00 00 00 02 00 00 00 0A 00 00 L 0  

,你可以或在讀取或寫入過程字節被刪除無法看到以某種方式(或增加,有時也會發生)

+0

您是否試過在十六進制編輯器中查看結果文件以查看它出錯的位置?或者複製一個文本文件,比較容易? – 2010-11-16 20:39:45

+0

你有什麼樣的問題?在函數中間隨機打開了什麼? – stonemetal 2010-11-16 20:42:27

+0

它是如何修改的?輸出與輸入有什麼不同? – 2010-11-16 20:43:18

回答

1

is.read(buffer,length)不保證讀取長度字節。

我忘記了out.write是否也是如此。

+0

+1。你需要調用'is.gcount()'來告訴讀了多少字節。 – 2010-11-16 20:50:49

+0

,但他用seekg(),tellg()檢查了長度,並且他使用了ios :: binary標誌,它應該確保EOF不帶有任何二進制0,但帶有真正的EOF。 – Pyjong 2010-11-16 23:06:44

+0

知道有要讀取的len字節不足以假定讀取len字節實際上讀取len字節。 – Joshua 2010-11-17 17:36:06

0

我認爲

ifstream src(source.c_str(), ios::binary); 
ofstream dest(destination.c_str(), ios::binary | ios::trunc); 
dest << src.rdbuf(); 
src.close(); 
dest.close(); 

會做的伎倆。

+0

除非您想檢查錯誤(並且如果您不檢查,則不要),否則不需要顯式調用close。讓它掉到範圍之外,析構函數會清理乾淨。 – 2010-11-16 22:26:40

0

允許作出這樣的一個位整潔:

// Pass strings by const reference (just good habit) 
// But may also save a copy. And it indicates that the function should 
// not be messing with the name! 
int Open(std::string const& Name, std::string const& out) 
{ 
    // Declare variables as close to use as possable. 
    // It is very C-Like to declare all the variables at the 
    // head of a function. 

    // Use the constructor to open the file. 
    std::ifstream is(Name.c_str(), ios::binary); 
    if (!is) // Failed to open 
    { return -1; 
    } 

    // get length of file: 
    is.seekg (0, ios::end); 
    std::size_t length = is.tellg(); // Use the correct type. int is not correct 
    is.seekg (0, ios::beg); 

    // allocate memory: 
    // Using new/delete is risky. It makes the code not exception safe. 
    // Also because you have to manually tidy up the buffer you can not 
    // escape early. By using RAII the cleanup becomes automative and there 
    // is no need to track resources that need to be tidied. 
    // 
    // Look up the concept of RAII it makes C++ lfe so much easier. 
    // std::vector implements the new/delete internally using RAII 
    std::vector<char> buffer(length); 

    std::size_t read = 0; 
    do 
    { 
     // read does not gurantee that it will read everything asked for. 
     // so you need to do int a loop if you want to read the whole thing 
     // into a buffer. 
     is.read(&buffer[read], length - read); 
     std::size_t amount = is.gcount(); 
     if (amount == 0) 
     { return -2; // Something went wrong and it failed to read. 
     } 
     read += amount; 
    } while(length != read); 


    fstream out(out.c_str(), ios::binary); 
    if (!out) 
    { return -3; // you may want to test this before spending all the time reading 
    } 


    // Probably need to loop like we did for read. 
    out.write(&buffer[0], length); 

    return 0; 
} 
+0

你的代碼和我的結果沒有什麼不同,你有什麼建議嗎? – 2010-11-17 17:58:19

+0

@Dean輝光:它應該看起來像你的。但整理好了,整潔。 – 2010-11-17 18:31:46

1

傳遞ios_base::binaryfstream的構造函數未指定(in和/或out也必須被提供)。

爲了避免這種情況,您可以使用ofstream(注意ex'0')代替out而不是fstream。作爲獎勵,由於ofstream的ctor在默認情況下創建文件,因此這將避免首先帶有「w」標誌的fopen

1

通常,文件以換行符結束。那0d0a(「\ r \ n」)可能不是源文件的可讀部分。 Windows通常使用「\ r \ n」作爲換行符,而UNIX只使用「\ n」。出於某種原因,當它寫入一個新文件時,它僅使用0a作爲最終換行符。如果您閱讀並複製您第一次編寫的文件,會發生什麼情況可能會很有趣。

簡而言之,這只是在使用Windows系統時遇到的那種問題。 :D

要破解它,你總是可以無條件地寫一個額外的「\ r」作爲你輸出的最後一個東西。