Plantilla para trabajar con archivos en lenguaje C.

Iniciado por NOB2014, 11 Abril 2017, 18:41 PM

0 Miembros y 2 Visitantes están viendo este tema.

NOB2014

Hola, gente ¿cómo están?
Lo que me trae en este caso no es para pedir ayuda porque el programa no funciona, lo que quisiera es que me digan que debería cambiar, que les parece, ¿está bien encarado?, estoy consiente que esto se lo debería preguntar a un profe o a un amigo, pero como ya algunos conocen por mi edad (65) no tengo ni una cosa ni la otra,-
Es todo, espero que alguien con mucho tiempo lo revice, no tengo ningún apuro. -   

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 80

void copiaDeSeguridad( FILE *ptrGuiaTel, FILE *ptrGtTemp ); //GT0001
void ingresarFrase( char frase[] ); //GT0002
void copiar( FILE *ptrGuiaTel, FILE *ptrGtTemp, char frase[] ); //GT0003
void errorEscritura( FILE *ptrGuiaTel, FILE *ptrGtTemp ); //GT0004
void mensaje( void );


int main( int argc,char **argv ){
FILE *ptrGuiaTel = NULL, *ptrGtTemp = NULL;
char frase[MAX];

copiaDeSeguridad( ptrGuiaTel, ptrGtTemp ); //GT0001
ingresarFrase( frase ); //GT0002
copiar( ptrGuiaTel, ptrGtTemp, frase ); //GT0003

return EXIT_SUCCESS;
}


void copiaDeSeguridad( FILE *ptrGuiaTel, FILE *ptrGtTemp ){ //GT0001
char c, x;

if( !( ptrGuiaTel = fopen( "archGuiaTel.txt", "r" ))){
mensaje();
exit(1);
}
if( !( ptrGtTemp = fopen( "archGtTemp.txt", "w" ))){
mensaje();
exit(1);
}

c = fgetc( ptrGuiaTel );
while ( c != EOF ){
x = fputc( c, ptrGtTemp );
if (x != c){
mensaje();
exit(1);
}
c = fgetc( ptrGuiaTel );
}

if( ( fclose( ptrGuiaTel ) ) ){
mensaje();
exit(1);
}
if( ( fclose( ptrGtTemp ) ) ){
mensaje();
exit(1);
}
}

void ingresarFrase( char frase[] ){ //GT0002
int ok=0;

do{
printf( "\n Ingrese frase.....:" );
fgets( frase, MAX, stdin );
ok = strlen( frase );
}while( ok <= 1 );
}

void copiar( FILE *ptrGuiaTel, FILE *ptrGtTemp, char frase[] ){ //GT0003

if( !(ptrGuiaTel = fopen( "archGuiaTel.txt", "a" ))){
mensaje();
exit(1);
}

fprintf( ptrGuiaTel, "%s", frase );

if( fflush( ptrGuiaTel ) != 0){
mensaje();
fclose( ptrGuiaTel );
errorEscritura( ptrGuiaTel, ptrGtTemp ); //GT0004
exit(1);
}

if( ( fclose( ptrGuiaTel ) ) ){
mensaje();
exit(1);
}
}

void errorEscritura( FILE *ptrGuiaTel, FILE *ptrGtTemp ){ //GT0004

if( rename("archGtTemp.txt","archGuiaTel.txt") !=0 ){
mensaje();
exit(1);
}

if(remove( "archGuiaTel.txt") !=0 ){
mensaje();
exit(1);
}
}

void mensaje( void ){
int ch, a;

printf( "\n Ha ocurrido un error y el programa finaliza sin cambios en el archivo." );
printf( "\n Pulse una tecla para continuar..."); a = getchar();
if( a != '\n') while ((ch = getchar()) != EOF && ch != '\n');
}

/*
GT0001 - Funcion copiaDeSeguridad
Efectuo una copia del archivo original por si fallara la escritura en el mismo, si esto
ocurriera renombro la copia con el mismo nombre que el archivo original y a este lo borro,
con esto me aseguro que el archivo en disco no quede corrupto. -
Si fallara la apertura de los archivos archGuiaTel.txt o archGtTemp.txt imprimo un mensaje
y cierro el programa (mensaje y exit(1)), lo mismo ocurrira si falla la escritura en el archivo temporal (if (x != c){).-
Si la apertura de los 2 archivos es correcta como asi la escritura, solo queda constatar si
el cierre de los mismos ocurre sin errores, de lo contrario se procedera de la misma manera que en la apertura de los mismos (mensaje y exit (1). -
Nota: En esta funcion se abre y se cierra el archivo "archGtTemp.txt".
//GT0002 - Funcion ingresarFrase   
El do-while es para que no se pueda salir de la funcion si no se ha ingresado por lo menos
un dígito.-
//GT0003 - Funcion copiar
Con fprintf( ptrGuiaTel, "%s", frase ); copio la frase en el buffer intermedio y con fflush
copio la frase desde el buffer al disco rigido(archGuiaTel.txt).-
Verifico si la apertura y cierre del archivo ocurre sin errores.-
En el caso de que fallara fflush llamo a la (//GT0004) funcion errorEscritura para renombrar el archivo archGtTemp.txt por archGuiaTel.txt para luego borrar el
                archivo original que seguramente si no se pudo escribir es porque está corrupto(al final con remove lo borro). -
*/


Saludos.
abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor y cuando lo abrazas dejan de causar dolor.-

MAFUS

No lo he probado pero estilísticamente está mal.

Usas los argumentos de las funciones como una forma de declarar variables locales. Los argumentos solo deberían usarse para que las funciones se comunicasen datos entre llamadas.

Cuando usas argumentos el compilador genera espacio en la pila para alojar dicho dato y después copia el dato que se va a pasar en esa nueva localidad.

He visto que llevas usando esta técnica desde hace tiempo, pero deberías cambiarla lo más pronto posible: declarar variables locales dentro del cuerpo de las funciones y usar los argumentos únicamente para pasar datos.

NOB2014

Hola.
No logro que me caiga la ficha del todo con lo que propones, te pediría tan solo unos minutos para que me hagas una pequeña función diciéndome lo que hago mal y como seria la forma correcta de hacerlo. -

Gracias MAFUS.
Un gran saludo.
abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor y cuando lo abrazas dejan de causar dolor.-

MAFUS

Así es tu código corregido:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 80

void copiaDeSeguridad( void );
void ingresarFrase( char frase[] );
void copiar( char frase[] );
void errorEscritura( void );
void mensaje( void );

int main( void ){
char frase[MAX];

copiaDeSeguridad( );
ingresarFrase( frase );
copiar( frase );

return EXIT_SUCCESS;
}


void copiaDeSeguridad( void ){
    FILE *ptrGuiaTel;
    FILE *ptrGtTemp;
char c, x;

if( !( ptrGuiaTel = fopen( "archGuiaTel.txt", "r" ))){
mensaje();
exit(1);
}
if( !( ptrGtTemp = fopen( "archGtTemp.txt", "w" ))){
mensaje();
exit(1);
}

c = fgetc( ptrGuiaTel );
while ( c != EOF ){
x = fputc( c, ptrGtTemp );
if (x != c){
mensaje();
exit(1);
}
c = fgetc( ptrGuiaTel );
}

if( ( fclose( ptrGuiaTel ) ) ){
mensaje();
exit(1);
}
if( ( fclose( ptrGtTemp ) ) ){
mensaje();
exit(1);
}
}

void ingresarFrase( char frase[] ){
int ok=0;

do{
printf( "\n Ingrese frase.....:" );
fgets( frase, MAX, stdin );
ok = strlen( frase );
}while( ok <= 1 );
}

void copiar( char frase[] ){
    FILE *ptrGuiaTel;
   
if( !(ptrGuiaTel = fopen( "archGuiaTel.txt", "a" ))){
mensaje();
exit(1);
}

fprintf( ptrGuiaTel, "%s", frase );

if( fflush( ptrGuiaTel ) != 0){
mensaje();
fclose( ptrGuiaTel );
errorEscritura( );
exit(1);
}

if( ( fclose( ptrGuiaTel ) ) ){
mensaje();
exit(1);
}
}

void errorEscritura( void ){

if( rename("archGtTemp.txt","archGuiaTel.txt") !=0 ){
mensaje();
exit(1);
}

if(remove( "archGuiaTel.txt") !=0 ){
mensaje();
exit(1);
}
}

void mensaje( void ){
int ch, a;

printf( "\n Ha ocurrido un error y el programa finaliza sin cambios en el archivo." );
printf( "\n Pulse una tecla para continuar..."); a = getchar();
if( a != '\n') while ((ch = getchar()) != EOF && ch != '\n');
}

NOB2014

Hola, ¿cómo están?
Gracias MAFUS por el código y gracias por el consejo, estaba cometiendo un error de primer grado, lo voy a tener muy en cuenta de aquí en más. --
La ayudita que les pido ahora es la siguiente, alguien me podría decir como hacer para que falle fflush,
(línea 43) para saber el comportamiento total del programa necesito que esto ocurra, intente abrir el archivo archGuiaTel.txt (línea 36) para lectura pero no me ocasiona un error, simplemente no escribe la frase, pero el programa termina normalmente. -   
Es todo y espero puedan darme la respuesta. -

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 80

void ingresarFrase( char frase[] );
void copiar( char frase[] );
void errorEscritura( void );
void copiaDeSeguridad( const char *GtTxt, const char *GtBak );
void mensaje( void );
 
int main( void ){
char frase[MAX];

ingresarFrase( frase );
copiar( frase );
copiaDeSeguridad( "archGuiaTel.txt","archGuiaTel.bak" );

return EXIT_SUCCESS;
}
 
void ingresarFrase( char frase[] ){
int ok=0;

do{
printf( "\n Ingrese frase.....:" );
fgets( frase, MAX, stdin );
ok = strlen( frase );
}while( ok <= 1 );
}
       
void copiar( char frase[] ){
FILE *ptrGtTxt;

if( !(ptrGtTxt = fopen( "archGuiaTel.txt", "a" ))){
mensaje();
exit(1);
    }

fprintf( ptrGtTxt, "%s", frase );

if( fflush( ptrGtTxt ) != 0){
mensaje();
fclose( ptrGtTxt );
errorEscritura( );
exit(1);
}

if( ( fclose( ptrGtTxt ) ) ){
mensaje();
exit(1);
}
}

void errorEscritura( void ){
if(remove( "archGuiaTel.txt" ) !=0 ){
mensaje();
exit(1);
}

if( rename( "archGuiaTel.bak","archGuiaTel.txt") !=0 ){
mensaje();
exit(1);
}
}

void copiaDeSeguridad( const char *GtTxt, const char *GtBak ){
FILE *ptrGtTxt, *ptrGtBak; 
char c, x;

if( !( ptrGtTxt = fopen( GtTxt, "a" ))){
mensaje();
exit(1);                               
}
if( !( ptrGtBak = fopen( GtBak, "w" ))){
mensaje();
exit(1);                               
}
     
c = fgetc( ptrGtTxt );
while ( c != EOF ){
x = fputc( c, ptrGtBak );
if (x != c){
mensaje();
exit(1);                               
}
c = fgetc( ptrGtTxt );
}
     
if( ( fclose( ptrGtTxt ) ) ){
mensaje();
exit(1);                               
}
if( ( fclose( ptrGtBak ) ) ){
mensaje();
exit(1);                               
}
}

void mensaje( void ){
int ch, a;

printf( "\n Ha ocurrido un error y el programa finaliza sin cambios en el archivo." );
printf( "\n Pulse una tecla para continuar..."); a = getchar();
    if( a != '\n') while ((ch = getchar()) != EOF && ch != '\n');
}


saludos.
 
abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor y cuando lo abrazas dejan de causar dolor.-

kuhi

Hola 😊👍🏻, tengo una duda: cuando usáis por ejemplo: void mensaje ( void )
Entiendo que estáis declarando una función tipo void pero no entiendo porqué ponéis void como parámetro... puede ser que estéis definiendo una función sin valor de retorno?
Me podéis explicar por favor??
Muchas gracias ❤️


Enviado desde mi iPhone utilizando Tapatalk
El conocimiento no ocupa lugar, somos libres de saber cuánto queramos...

MAFUS

Eso quiere decir que la función no acepta argumentos y no devuelve ningún dato. Es lo mismo que void mensaje(). Es una cuestión de estilos.

kuhi

Cita de: MAFUS en 28 Abril 2017, 10:09 AM
Eso quiere decir que la función no acepta argumentos y no devuelve ningún dato. Es lo mismo que void mensaje(). Es una cuestión de estilos.
Es más correcto utilizarlo así o es 100% idéntico? Saludos y gracias 😊👍🏻


Enviado desde mi iPhone utilizando Tapatalk
El conocimiento no ocupa lugar, somos libres de saber cuánto queramos...

NOB2014

Hola.
Pongo void en las funciones que no reciben parametros porque una vez leí que era una ayuda para el compilador pero por más que busco de donde lo saque, no lo encuentro, desde ese momento, en todas mis prácticas lo hago de esa manera. -
Aprovecho para decirles que encontré la manera para forzar a fflush que de error. -

Saludos.
abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor y cuando lo abrazas dejan de causar dolor.-

CalgaryCorpus

Un poco de historia.
Los primeros compiladores de C eran bastante rudimentarios y no hacian chequeos, suponiendo que el programador sabia lo que hacia. En particular los parametros de las funciones. Al inicio, el lenguaje C permitia no especificar parametros como en
int mifuncion()

y luego mas adelante invocar esa funcion asi:

valor = mifuncion( a, b, c );


y el compilador no reclamaba nada.

Con el tiempo, el lenguaje se estandarizo y le agregaron el que uno pueda especificar los tipos de los parametros, pero aun manteniendo la compatibilidad hacia atras, vale decir, si no especificabas nada, no habia chequeos, pero si especificabas algo, entonces habia chequeos.

En este caso, si ponias
int mifuncion(void)


entonces el compilador va a reclamar si invocas la funcion con algun parametro, pues al poner el void ahi, le estas pidiendo explicitamente al compilador que chequee, y este no va a permitir la invocacion con mas parametros.

Ahora ya no importa la compatibilidad hacia atras, si no pones parametros en la definicion de la funcion el compilador va a chequear que NO pases ningun parametro, del mismo modo si pones void entre los parentesis.

Resumen

  • mucho antes: no habia chequeo alguno
  • luego: chequeo si especificas void
  • ahora: chequeo siempre
Aqui mi perfil en LinkedIn, invitame un cafe aqui