2010-11-16 34 views
0

Je suis nouveau en C++ et je dois faire une tâche pour l'école.C++ ifstream/fstream corrompre des données

Je dois copier un fichier binaire * sans utiliser d'appels api ou de commandes intégrées au système. À l'école, nous utilisons une machine Windows.

J'ai cherché un peu, et j'ai trouvé que la meilleure façon de copier des données sans utiliser iostream (ifstream/fstream) est d'utiliser de toute api Voici le code que je utilise:

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; 
} 

isnt Out.exe fonctionne correctement, et après avoir regardé dans winhex.exe Je vois que les données ont été modefied, alors que je ne fais rien avec elle

quelqu'un peut-il me aider?

* le fichier est un simple bonjour programme mondial, il MessageBoxes "Bonjour tout le monde"

EDIT:

Désolé pour mon absence de réaction, il dormait. Quoi qu'il en soit, j'ai ouvert les deux programmes (le résultat et l'original) dans un éditeur hexadécimal. Il semble que tout ce que j'essaie cette ligne:

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  

Les changements dans ce:

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  

Comme vous pouvez ou ne peut pas voir en quelque sorte au cours du processus de lecture ou l'écriture d'un octet est supprimé (ou ajouté , ce qui arrive parfois aussi)

+0

Avez-vous essayé de regarder le fichier résultant dans un éditeur hexadécimal pour voir où cela s'est mal passé? Ou copier, disons, un fichier texte, qui serait plus facile à comparer? –

+0

Quel genre de problèmes avez-vous? Qu'est-ce qui se passe avec la fopen aléatoire au milieu de votre fonction? – stonemetal

+0

Comment est-il modifié? Comment la sortie diffère-t-elle de l'entrée? –

Répondre

1

is.read (buffer, length) n'est pas garanti pour lire les octets de longueur. J'oublie s'il en est de même pour out.write ou non.

+0

+1. Vous devez appeler 'is.gcount()' pour indiquer le nombre d'octets lus. –

+0

mais il a vérifié la longueur avec seekg(), tellg() et il a utilisé le drapeau ios :: binary qui devrait s'assurer que EOF ne vient pas avec un 0 binaire mais un EOF réel. – Pyjong

+0

Sachant qu'il y a lents octets à lire, il ne suffit pas de supposer qu'une lecture de len octets lit réellement len ​​octets. – Joshua

0

Je pense que

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

ferait l'affaire.

+0

Pas besoin d'appeler explicitement à proximité, sauf si vous voulez vérifier les erreurs (et si vous ne vérifiez pas alors ne pas). Laissez-le tomber hors de portée et le destructeur va ranger. –

0

permet de faire qu'un peu plus propre:

// 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

Le résultat de votre code ne diffère pas du mien, avez-vous d'autres suggestions? –

+0

@Dean lueur: Il est censé ressembler à la vôtre. Mais rangé et rendu plus propre. –

1

En passant seulementios_base::binary-fstream « s cteur n'est pas spécifiée (in et/ou out doit être fourni aussi). Pour éviter cela, vous pouvez utiliser ofstream (notez l'ex 'o') pour out au lieu de fstream. En prime, cela éviterait d'avoir à fopen d'abord avec le drapeau "w" puisque le ctor de ofstream crée le fichier par défaut.

1

Généralement, les fichiers se terminent par un saut de ligne. Ce 0d0a ("\ r \ n") peut ne pas être une partie lisible du fichier source. Windows utilise généralement "\ r \ n" pour le retour à la ligne, tandis que UNIX utilise simplement "\ n". Pour une raison quelconque, quand il écrit un nouveau fichier, il utilise juste 0a pour le retour à la ligne final. Il pourrait être intéressant de voir ce qui se passe si vous lisez et copiez le fichier que vous avez écrit la première fois.

La réponse courte est, c'est juste le genre de problème qui surgit lorsque vous utilisez un système Windows. Pour le pirater, vous pouvez toujours écrire inconditionnellement un "\ r" comme dernière chose que vous produisez.