[c++] Przepisanie dowolnego pliku tak żeby działał

Witam serdecznie. Potrzebuje właśnie móc odczytać plik w taki sposób żeby zapisując znak po znaku do nowego pliku otrzymać identyczną kopię która będzie działać. Napisałem coś takiego:

#include iostream
#include cstdio

int main() {
    int a = 0;
    char znak;
FILE * inp = fopen ("c:/file.rar", "r");
FILE * oup = fopen ("c:/output.rar", "w");
znak = getc( inp );
    while( znak != EOF )
    {
        fprintf( oup, "%c", znak );
        znak = getc( inp );
    }
fclose( inp );
fclose( oup );   
return 0;
}

 

Ale plik wynikowy nie da się rozpakować. Co robić?

Hmmm… podejrzewam znaki końca linii.

Na Windowsie linia tekstu kończona jest przez CR+LF (w C++ “\r\n”), natomiast w standardzie C i C++ koniec linii oznaczany jest samym LF (’\n’).

Podczas czytania danych z pliku, sekwencje CR+LF zastępowane są przez LF, a przy zapisywaniu LF zmieniane na CR+LF.

Jeśli gdzieś w pliku będziesz miał samo LF to przy odczycie dostaniesz LF, które przy zapisie zmieni się na CR+LF i plik ci się popsuje :stuck_out_tongue:

Powinieneś otwierać pliki w trybie binarnym (opcja b, “rb” do odczytu, “wb” do zapisu, itp.), wtedy takie konwersje nie będą zachodzić.

Poza tym używanie funkcji stricte tekstowych (getc, fprintf, itp.) do operowania na plikach binarnych nie jest zbyt eleganckie :wink:

I jeszcze zmienna ‘znak’ powinna być typu int, bo getc może zwrócić EOF(0xFFFFFFFF), który obcięty do jednego bajta jest nieodróżnialny od bajta 0xFF, który może normalnie wystąpić w pliku.

Dzięki za odpowiedź. Wiele to wyjaśniło ale wciąż nie wszystko.

Przede wszystkim wydaje mi się, że używasz nieprawidłowej funkcj do zapisu danych do pliku. Masz dane binarne, a traktujesz je jak dane znakowe.  Bardziej odpowiednia funkcja to fputc.

Skoro pisziszesz w C++ to nie lepiej użyć ifstream i ofstream?

Proszę mi wybaczyć ale do tej pory korzystałem z c++ przede wszystkim na studiach do rozwiązywania równań różniczkowych czy tam metody simpsona, rk4 itp. odczyt i zapis z pliku odbywał się tylko po intach i nie było problemu.

PIsz jak Ci wygodnie :wink: Moim zdaniem użycie klas z C++ jest łatwiejsze. Ustawiasz flagę otwieranego pliku na binary i  dalej się nie martwisz.

Udało mi się to zrobić tak:

#include fstream
#include iostream

int main(){

std::fstream plikin( "C:/input.rar", std::ios::in | std::ios::binary);
std::fstream plikout( "C:/output.rar", std::ios::out | std::ios::binary);

char bufor[1];
int length,i;
//rozmiar pliku
    plikin.seekg( 0, std::ios::end );
    length = plikin.tellg();
    plikin.seekg( 0, std::ios::beg );
//rozmiar pliku
for(i=0;ilength;i++){
plikin.read( bufor, 1 );
plikout.write( bufor[0], 1 );
}
return 0;
}

Możesz jeszcze użyć metod CopyFile lub CopyFileEx  z WinAPI.

http://msdn.microsoft.com/en-us/library/windows/desktop/aa363851(v=vs.85).aspx

@Up