[C con Clase] problemas con la posicion del puntero en un fichero, funciones fread, frwite, fseek etc.

Salvador Pozo salvador en conclase.net
Lun Mar 5 10:35:34 CET 2012


El pasado 2012-03-04 22:23:19, Albert_Munich escribió:
 
A> Muchas gracias por la explicación,
A> he corregido lo de SEEK_CUR, y ahora en teoria, lee la palabra, el cursor
A> se queda despues de la palabra, y para sobreescribirla utilizo
A> fseek(fichero, (-1)*sizeof(struct t_palabra), SEEK_CUR);
A> y tampco me funciona, me repite todo el rato la segunda palabra, el mismo
A> problema de siempre. no entiendo el porque, ya que despues del fwrite, el
A> cursor queda detras d la palabra modificada, y con el siguiente fread
A> dentro dl while, se tendria que leer la palabra que toca. no se como
A> solucionarlo xk x logica lo haria asi, xo nose donde esta el error
A> informatico, o si esta equivocada la logica aplicada.
A> Me podrias ayudar? esque estoy aprendiendo a programar x mi cuenta y cuesta
A> 1 poco.

Hola:

Bueno, mucho me temo que esta es una de esas "cosas raras" que pasan con la programación, cuando el lenguaje está limitado con respecto a las implementaciones reales de los sistemas operativos.

Puede que me equivoque en el origen del problema (si es así, que alguien me corrija), pero me temo que este comportamiento de las funciones de ficheros está relacionada con el modo en que Windows implementa el sistema de archivos.

En C++, usando streams, es posible que esto no pase, pero luego llegamos a esto.

Los ficheros de acceso aleatorio pueden tener punteros de escritura y lectura diferentes, es decir, el punto en que se lee del fichero no tiene por qué ser el mismo en el que se escribe. Esto es evidente si el fichero se abre en modo "append", en los que podemos leer de cualquier punto, pero sólo se puede escribir al final. Pero lo cierto es que puede pasar en todos los tipos de ficheros.

En tu programa fseek coloca los dos cursores del fichero, el de escritura y el de lectura, a a una posición anterior, pero al escribir los nuevos valores del registro sólo se actualiza el cursor de escritura, y el de lectura se mantiene en la misma posición. Por eso siempre leemos el segundo registro.

Los streams de C++ disponen de funciones diferentes para colocar los cursores de lectura y escritura: seekg y seekp, y lo mismo para leer esas posiciones: tellg y tellp. Por lo que esto resulta más evidente.

La solución es simple: colocar el cursor antes de realizar cada lectura. Para esto necesitarás un índice. 

Otro problema con tu programa es el uso de feof (creo que lo habías preguntado anteriormente).

El bucle tiene esta forma:
----8<------
while(!feof(fichero)) {
    fread(&palabra, sizeof(palabra), 1, fichero);
    ...
}
----8<------

Ahora imaginemos que hemos leído el último registro, y volvemos a repetir el bucle.
Primero, la condición de fin de fichero es falsa, ya que es una bandera (un flag) que se almacena en la estructura FILE, y que sólo se actualiza después de una operación de lectura o escritura.
Como feof es falsa, !feof es verdadera, y se ejecuta el bucle. Leemos una palabra, pero el cursor de lectura está al final del fichero, de modo que la lectura falla, y se activa la bandera de fin de fichero. Sin embargo, se procesa el registro.
Cuando fread falla, el registro no se lee, de modo que palabra mantiene su valor actual. Esto hace, en un bucle normal (sin fseek), que el último registro se procese dos veces. En tu caso, el último registro se procesa hasta el infinito.

En el caso de los ficheros hay que modificar este bucle:
----8<------
while(!feof(fichero)) {
    if(fread(&palabra, sizeof(palabra), 1, fichero) {
       ...
    }
}
----8<------

Es decir, sólo procesamos el registro leído si realmente lo hemos leído.

Sobre este tema puede consultar la página de C con Clase sobre archivos:
http://c.conclase.net/ficheros/index.php

Hasta pronto.

-- 
Salvador Pozo (Administrador)
mailto:salvador en conclase.net


Más información sobre la lista de distribución Cconclase