Lectura y modificacion de archivo

Iniciado por m@o_614, 10 Septiembre 2013, 13:12 PM

0 Miembros y 1 Visitante están viendo este tema.

m@o_614

Saludos tengo el siguiente codigo que me lee un archivo de texto y despues lo modifica, en todos los lugares donde se encuentre 1's los intercambia por 5's, la lectura del archivo lo hace bien porque ya verifique y si me ubica los unos del texto el problema es para poder cambiarlos a 5, y no se donde esta el error

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

/*
   Objetivo de la prueba: En una archivo de texto que contiene caracteres alfanuméricos,
   intercambiar el  '1' por el  ' 5' en donde quiera que ocurra esa incidencia en el documento.
   El archivo debe aparecer sin ningún 1, y en su lugar los cincos equivalentes.
*/

int main()
{
   FILE *fd;
   char letra;
   if((fd = fopen("F:\\archivo_practica11.txt","r+"))!=NULL)
   {
       while(!feof(fd))
       {
           fread(&letra,sizeof(char),1,fd);
           if(letra == '1')
           {
                letra = '5';
               fwrite(fd,sizeof(char),1,letra);
           }
       }
   }
   else
      printf("No se pudo abrir el archivo");
   return 0;
}


gracias

eferion

Cada vez que lees o escribes estás modificando el puntero interno del fichero.

Quiero decir... cuando tu abres un archivo, internamente se crea un puntero de posición. Este puntero es el que indica a partir de donde se van a iniciar las operaciones de lectura / escritura. Cuando tu realizas una de estas operaciones sobre el fichero, dicho puntero se actualiza. Esta es la razón por la que sucesivas escrituras no machacan la misma información sino que se concatenan.

Tu estás leyendo un carácter y, si éste es un '1', escribes un '5' en el fichero. El problema es que al lanzar la operación de lectura el puntero interno ha avanzado una posición y el '5' machaca la posición siguiente.

Para evitar esto tienes que hacer esto:


fread(&letra,sizeof(char),1,fd);
            if(letra == '1')
            {
                fseek( fd, -1, SEEK_CUR );
                 letra = '5';
                fwrite(fd,sizeof(char),1,letra);
            }


De esta forma vuelves a posicionar el puntero sobre el carácter '1' y la operación de escritura machacará dicho carácter.

No he compilado el código, pero debería funcionar.

rir3760

Otro error es utilizar la función feof para controlar el bucle (con ello se realiza una iteración de mas) y uno mas es el orden de los argumentos de la función fwrite:
fwrite(fd, sizeof(char), 1, letra);
El primer argumento debe ser la dirección base (de tipo "void *") y el ultimo el archivo a procesar (de tipo "FILE *").

Y no necesitas del encabezado <unistd.h>. Si no tienes una referencia sobre las funciones de la biblioteca estándar de C (C90) deberías conseguir una, mientras eso sucede una aceptable es Standard C.

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

m@o_614

#3
Gracias por sus respuestas, le habia hecho al codigo unos cambio de los que me habian dicho, pero ahora sucede que aunque el programa si cambia los 1's por los 5's ahora se cicla infinitamente, y creo que el problema esta en el fseek, porque le puse un contador en el ciclo para que me contara cuantos unos aparecian en el texto y si le ponia fseek no me imprimia nada y si se lo quitaba ya me imprimia correctamente

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

/*
    Objetivo de la prueba: En una archivo de texto que contiene caracteres alfanuméricos,
    intercambiar el  '1' por el  ' 5' en donde quiera que ocurra esa incidencia en el documento.
    El archivo debe aparecer sin ningún 1, y en su lugar los cincos equivalentes.
*/

int main()
{
   FILE *fd;
   char letra;
   int i = 0;
   if((fd = fopen("F:\\archivo2.txt","r+"))!=NULL)
   {
       while(!feof(fd))
       {
           fread(&letra,sizeof(char),1,fd);
           if(letra == '1')
           {
               fseek(fd,-1,SEEK_CUR);
               letra = '5';
               fwrite(&letra,sizeof(char),1,fd);
               i++;
           }
       }
       printf("%d",i);
   }
   else
      printf("No se pudo abrir el archivo");
   return 0;
}

eferion

Ese printf está fuera de los ciclos... salta cuando haya terminado de procesar el archivo...

if((fd = fopen("F:\\archivo2.txt","r+"))!=NULL)
   {
       while(!feof(fd))
       {
           // ...
       }
       printf("%d",i);
   }


y si has abierto el archivo, no te olvides de cerrarlo al final con fclose.

m@o_614

#5
En realidad ese printf y el contador ps no sirven para nada, solo queria saber si me estaba contando bien cuantos unos habia, pero ahora ya me di cuenta que el fseek no es el problema!! el problema es cuando le asigno a letra un nuevo valor o en el fwrite, no se bien

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

/*
   Objetivo de la prueba: En una archivo de texto que contiene caracteres alfanuméricos,
   intercambiar el  '1' por el  ' 5' en donde quiera que ocurra esa incidencia en el documento.
   El archivo debe aparecer sin ningún 1, y en su lugar los cincos equivalentes.
*/

int main()
{
  FILE *fd;
  char letra;
  int n;
  if((fd = fopen("F:\\archivo2.txt","r+"))!=NULL)
  {
         fread(&letra,sizeof(char),1,fd);
          if(letra == '1')
          {
              fseek(fd,-1,SEEK_CUR);
              letra = '5';
              printf("%c",fgetc(fd));
  }
  else
     printf("No se pudo abrir el archivo");
  return 0;
}


en el printf que tiene el fgetc  queria ver si la variable letra habia cambiado a 5 pero ya vi que me sigue imprimiendo los unos, me imagino que por ahi esta el problema

eferion


fread(&letra,sizeof(char),1,fd);
           if(letra == '1')
           {
               fseek(fd,-1,SEEK_CUR);
               letra = '5';
               printf("%c",fgetc(fd));
            }


A ver tu estás haciendo "letra = 5", es decir, estas asignando a una variable de tu programa el valor 5 y, acto seguido, lees del archivo con fgetc... obviamente la asignación no va a afectar al archivo si no le metes un fwrite.

Si quieres hacer esta comprobación tendrás que hacer algo así:


fread(&letra,sizeof(char),1,fd);
           if(letra == '1')
           {
               fseek(fd,-1,SEEK_CUR);
               letra = '5';
               fwrite( &letra, sizeof(char), 1, fd ); // primero modificamos el fichero
               fseek( fd, -1, SEEK_CUR ); // retrocedemos otra vez para poder leer
               printf("%c",fgetc(fd)); // y ahora si leemos lo que deberia ser un 5
            }

rir3760

Cita de: m@o_614 en 10 Septiembre 2013, 23:30 PMle habia hecho al codigo unos cambio de los que me habian dicho, pero ahora sucede que aunque el programa si cambia los 1's por los 5's ahora se cicla infinitamente
El problema se debe a que en los modos de actualización ("r+", "w+" y "a+") las operaciones de lectura y escritura no pueden realizarse una inmediatamente después de la otra. Siempre después de una operación de lectura se debe indicar la posición en el archivo mediante fseek o rewind si la intención es continuar con una operación de escritura (y al revés): lectura <==> posicionamiento <==> escritura.

En tu caso eso no sucede porque si el carácter '1' se encuentra en el archivo lo sobrescribes con un '5' y a continuación (en la siguiente iteración del bucle) tratas de leer el siguiente carácter, ahí falta la mentada llamada a función.

Para que el programa funcione correctamente se puede utilizar la función ftell para obtener las posiciones antes y después de la lectura del carácter:
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
   FILE *stream;
   long a;
   long b;
   char ch;

   if ((stream = fopen("Entrada.txt", "r+")) != NULL){
      while (a = ftell(stream), fread(&ch, 1, 1, stream) == 1){
         if (ch == '1'){
            b = ftell(stream);

            fseek(stream, a, SEEK_SET);
            ch = '5';
            fwrite(&ch, 1, 1, stream);
            fseek(stream, b, SEEK_SET);
         }
      }
     
      fclose(stream);
   }
   
   return 0;
}


Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

m@o_614

muchas gracias rir3760 nunca se me hubiera ocurrido que cuando haces una actualizacion no se puede leer y despues escribir luego. Una ultima pregunta, por que antes del fread siempre se tiene que utilizar el ftell???

rir3760

Cita de: m@o_614 en 12 Septiembre 2013, 01:58 AMpor que antes del fread siempre se tiene que utilizar el ftell?
Porque no sabemos de antemano si el carácter que vamos a leer cumplirá o no con la condición, si es igual a '1' debemos regresar a la posición anterior (ftell + fseek) y sobrescribir ese carácter (fwrite).

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language