2012-01-11 12 views
7

Tengo una tarea en C++. La tarea es pedir la conversión de un programa c a C++. A continuación es la pregunta:necesita ayuda para convertir c a C++ (error simple pero no se puede arreglar)

Se le pide que convertir la siguiente función C en una función de C++ y luego incrustarlo en un programa completo y probarlo. Observe que esta función copia un archivo binario de enteros y no un archivo de texto . El programa debe aceptar los argumentos (el archivo para copiar y el archivo que se va a copiar) desde la línea de comandos.

/* ==================== cpyFile ===================== 

This function copies the contents of a binary file 
of integers to a second file. 
Pre fp1 is file pointer to open read file 
fp2 is file pointer to open write file 
Post file copied 
Return 1 is successful or zero if error 
*/ 
int cpyFile (FILE *fp1, FILE *fp2) 
{ 
    /* Local Definitions */ 
    int data; 

    /* Statements */ 
    fseek (fp1, 0, SEEK_END); 
    if (!ftell (fp1)) 
    { 
    printf ("\n\acpyFile Error : file empty\n\n"); 
    return 0; 
    } /* if open error */ 
    if (fseek (fp1, 0, SEEK_SET)) 
    return 0; 
    if (fseek (fp2, 0, SEEK_SET)) 
    return 0; 

    while (fread (&data, sizeof (int), 1, fp1)) 
    fwrite (&data, sizeof (int), 1, fp2); 
    return 1; 
} /* cpyFile */ 

Hice lo que pude y logró convertirlo, pero por desgracia, cuando lo estoy usando, el archivo que consigo después de la copia está vacía. A continuación se muestra mi respuesta:

#include <fstream> 
#include <cstdlib> 
#include <iostream> 
using namespace std; 
int main(int argc,char* argv[]) 
{ 
    if(argc!=3) 
    {cerr<<"invalid number of arguments. must be 3."<<endl;exit(1);} 

    fstream fp1(argv[1],ios::in); 
    if(!fp1)+{cerr<<argv[1]<<" could not be opened"<<endl;exit(1);} 

    fstream fp2(argv[2],ios::out); 
    if(!fp2)+{cerr<<"file could not be found."<<endl;exit(1);} 


    int data; 

    fp1.seekg (0,ios::end); 
    if (!fp1.tellg()) 
    { 
    cout<<"\n\acpyFile Error : file empty\n\n"; 
    return 0; 
    } /* if open error */ 
    if (fp1.seekg (0, ios::beg)) 
    return 0; 
    if (fp2.seekg (0, ios::beg)) 
    return 0; 

    while (fp1.read (reinterpret_cast<char*>(&data), sizeof (int))) 
    { 
    fp2.seekp(0); 
    fp2.write (reinterpret_cast<char*>(&data), sizeof (int)); 
    } 
    return 1; 
} 

hice todo lo posible y todo está funcionando bien, excepto que cuando copiar un archivo binario, el archivo que me sale es vacía y no tengo ni idea de por qué.

+5

Un buen intento, lo recomiendo por darle una oportunidad decente en vez de simplemente pedirle a alguien que lo haga por usted. – dreamlax

+3

No hagas esto en tu tarea, pero para futuras referencias: 'std :: ofstream (argv [2]) << std :: ifstream (argv [1]);' –

+0

¿Por qué tienes 'fp2.seekp (0) '* in * the loop? – celtschk

Respuesta

7

Usted necesidad de abrir el archivo en modo binario, como otros han dicho, haciendo

fstream fp1(argv[1], ios::in | ios::binary); // combine ios::in with ios::binary 

fstream fp2(argv[2], ios::out | ios::binary); // combine ios::out with ios::binary 

O bien, puede hacer que se ifstream (en secuencia de archivo para sólo lectura) y ofstream (a cabo archivo corriente, para sólo escritura) y retire la ios::in y ios::out porque ifstream implica ios::in y ofstream implica ios::out:

ifstream fp1(argv[1], ios::binary); 

ofstream fp2(argv[2], ios::binary); 

que tiene que hacer esto porque si no lo hace, será traducido el archivo cuando se lee desde o escribir en él para cosas como convertir los finales de línea de \r\n o \r sólo \n, etc, que se hace un lío de su datos binarios que pueden tener esos bytes en ellos.

Este:

if (fp1.seekg (0, ios::beg)) 
    return 0; 

if (fp2.seekg (0, ios::beg)) 
    return 0; 

siempre hará que su declaración de código porque seekg devuelve el objeto de llamar a encenderlo. No es el equivalente a fseek en este sentido porque fseek devuelve 0 en caso de éxito. Por lo tanto, nunca se llega al ciclo while.Tome los de los if declaraciones para que se vea así:

fp1.seekg(0, ios::beg); 
fp2.seekg(0, ios::beg); 

O si usted tiene que tener la comprobación, que quiere hacer

if (!fp1.seekg (0, ios::beg)) // notice the added ! 
    return 0; 

if (!fp2.seekg (0, ios::beg)) // notice the added ! 
    return 0; 

Además, este (dentro de la while):

fp2.seekp(0); 

Está estableciendo el punto en el que va a escribir al principio del archivo. Entonces nunca escribirás nada más que al comienzo del archivo. Solo elimina esa línea por completo.

Además, tiene un return dentro del bucle que lo hace volver en la primera iteración. Mueva el return 1; fuera del bucle para que solo regrese después de que el bucle haya finalizado. No lo olvides, se malinterpreta debido al estilo inusual de la abrazadera.

+0

increíble. Hice lo que dijiste y funcionó. ¡gracias! – LebTech

0

archivos binarios necesitan ser abiertos específicamente en modo binario, por lo que cuando usted tiene fstream fp1(argv[1],ios::in); También debe agregar un ios :: binario para que de este modo: fstream fp1(argv[1], ios::in | ios::binary);

1

Cada vez que se lee un nuevo bloque de datos de fp1, rebobina fp2 al comienzo de la transmisión, esencialmente descartando lo que ya ha escrito en fp2. Intente mover fp2.seekp(0) fuera de su bucle principal.

0

En el código de C++ busca el comienzo del archivo de salida antes de escribir cada número y, por lo tanto, el archivo de salida tendrá como máximo 2 bytes de longitud.

+1

Será * al menos * 2 bytes de longitud. El tipo 'int' puede ser de cualquier tamaño, siempre que sea mayor o igual que 2 bytes. – dreamlax

+0

@dreamlax Tienes razón. Supongo que para mí es hora de ir a dormir –

1

Tiene algunos problemas. Yo empezaría por la fijación de este bit:

if (fp1.seekg (0, ios::beg)) 
    return 0; 
if (fp2.seekg (0, ios::beg)) 
    return 0; 

El método seekg devuelve una referencia a la istream se llama en adelante, por lo que la anterior es equivalente a esto:

fp1.seekg (0, ios::beg); 
if (fp1) // i.e., if fp1 is in a valid state (as opposed to e.g. end-of-file) 
    return 0; 
fp2.seekg (0, ios::beg); 
if (fp2) // i.e., if fp2 is in a valid state (as opposed to e.g. end-of-file) 
    return 0; 

lo que obviamente no es lo que querer.

Para depurar el código, puede usar sentencias como std::cout << "Got to line " << __LINE__ << std::endl; para averiguar qué partes del programa se están ejecutando realmente. Eso habría encontrado el problema anterior bastante rápido.

+0

No te olvides de '__LINE__':' cout << "Llegué a la línea" << __LINE__ << endl; ':) –

+0

@SethCarnegie: Robado, gracias. ;-) Empecé a sugerir un tipo de mensaje diferente ('" Llegué al ____ while-loop "'), y luego solo migré a medias al enfoque basado en línea antes de publicarlo. :-P – ruakh

+1

Las declaraciones de depuración como estas son útiles para programas pequeños; mucha gente siempre dice "aprende a usar un depurador", pero la verdad es que todos en esta etapa ya saben cómo usar las declaraciones impresas, por lo que, por el momento, es probablemente más productivo hacerlo. En definitiva, aprender a usar un depurador es una habilidad invaluable, pero a veces es más fácil poner 'printf' o' cout' en vez de configurar puntos de interrupción, ver variables, etc., etc. – dreamlax

Cuestiones relacionadas