2010-11-16 4 views
0

Я новичок в C++, и я должен выполнить задание для школы.C++ ifstream/fstream повреждающие данные

Мне нужно скопировать двоичный файл без использования вызовов api или системных интегрированных команд. В школе мы используем машину для окон.

Я искал вокруг немного, и я узнал, что лучший способ для копирования данных без использования какой-либо 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, в то время как я с этим ничего

Может кто-нибудь мне помочь не делать?

* файл является простым привет мира программы, она MessageBoxes "привет мира"

EDIT:

Извините за мою невосприимчивость, он спит. В любом случае, я открыл обе (исходные и исходные) программы в шестнадцатеричном редакторе. Кажется, что все, что я пытаюсь эту строку:

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

Вы пробовали посмотреть полученный файл в шестнадцатеричном редакторе, чтобы узнать, где он поступил неправильно? Или копировать, скажем, текстовый файл, который будет проще сравнивать? –

+0

Какие проблемы у вас есть? Что происходит со случайным фоном в середине вашей функции? – stonemetal

+0

Как это изменить? Как выход отличается от входа? –

ответ

1

is.read (buffer, length) не гарантированно считывает байты длины.

Я забыл, что это верно для out.write или нет.

+0

+1. Вам нужно вызвать 'is.gcount()', чтобы указать, сколько байтов было прочитано. –

+0

, но он проверил длину с помощью seekg(), tellg(), и он использовал ios :: двоичный флаг, который должен гарантировать, что EOF не приходит с каким-либо двоичным 0, а реальным EOF. – Pyjong

+0

Зная, что для чтения len-байтов недостаточно, чтобы предположить, что чтение len-байтов фактически считывает len-байты. – Joshua

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

Не нужно явно вызывать закрытие, если вы не хотите проверять наличие ошибок (и если вы не проверяете, тогда dont). Пусть он выпадет из сферы действия, и деструктор будет убирать. –

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

Результат вашего кода не отличается от моего, есть ли у вас какие-либо другие предложения? –

+0

@Dean glow: Он должен выглядеть как ваш. Но прибрал и сделал аккуратно. –

1

Передача толькоios_base::binary к fstream «ы т е р не определен (in и/или out должны быть поставлены слишком).

Чтобы избежать этого, вы можете использовать ofstream (обратите внимание на exra 'o') для out вместо fstream. В качестве бонуса это позволит избежать необходимости сначала fopen с флагом «w», так как ctor ofstream создает файл по умолчанию.

1

Как правило, файлы заканчиваются символом новой строки. То, что 0d0a ("\ r \ n") может не быть читаемой частью исходного файла. Обычно Windows использует «\ r \ n» для новой строки, а UNIX использует только «\ n». По какой-то причине, когда он пишет новый файл, он использует только 0a для окончательной новой строки. Может быть интересно посмотреть, что произойдет, если вы прочитаете и скопируете файл, который вы написали в первый раз.

Короткий ответ: это просто проблема, возникающая при использовании системы Windows. : D

Чтобы взломать его, вы всегда можете безоговорочно написать дополнительный «\ r» в качестве последнего вывода.

Смежные вопросы