2010-11-16 247 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”作为你输出的最后一个东西。