C/Visual C - Problema con fseek();

   
Vista:

Problema con fseek();

Publicado por Diego (87 intervenciones) el 09/07/2016 17:49:44
BUenas tardes, tengo un problema y no logro saber el porqué.

Como no se bien como es que quedan las posiciones de un archivo tras una lectura o escritura.
Decidí guardar la posicion que tiene el archivo antes de que lea o escriba y luego que termine de leer/escribir con fseek hago que retorne a la posicion previamente guardada.
Este es el codigo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
int LeerSubCabecera(struct datos *cabecera, FILE **entrada)
{
	int leidos, escritos;
	long pos;
	pos = ftell(*entrada);
	printf("posicion = %ld\n", pos);
	leidos = fread(&cabecera->tamanio, sizeof(unsigned int), 1, *entrada);
	if (leidos != 1){
		return 18;
	}
	pos = ftell(*entrada);
	printf("posicion = %ld\n", pos);
	leidos = fread(&cabecera->fecha_modificacion, sizeof(unsigned int), 1, *entrada);
	if (leidos != 1){
		return 18;
	}
	pos = ftell(*entrada);
	printf("posicion = %ld\n", pos);
	leidos = fread(&cabecera->reservado1, sizeof(long long), 1, *entrada);
	if (leidos != 1){
		return 18;
	}
	pos = ftell(*entrada);
	printf("posicion = %ld\n", pos);
	leidos = fread(&cabecera->reservado2, sizeof(long long), 1, *entrada);
	if (leidos != 1){
		return 18;
	}
		unsigned int tamanio_cadena = 0;
		char buffer = 'X';
		long posicion = 0;
		posicion = ftell(*entrada);
		printf("posicion = %ld\n", posicion);
		leidos = fread(&buffer, sizeof(char), 1, *entrada);
		while ((leidos == 1) && (buffer != '\0')){
			++tamanio_cadena;
			printf("%c\n", buffer);
			leidos = fread(&buffer, sizeof(char), 1, *entrada);
		}
		if (leidos != 1){
			return 18;
		}
		printf("posicion = %ld\n", posicion);
		fseek(*entrada, 0L, posicion);
		posicion = ftell(*entrada);
		printf("se volvio a la posicion: %ld\n", posicion);
		printf("tamanio cadena = %u\n", tamanio_cadena);
		++tamanio_cadena;
		cabecera->nombre = (char *)malloc(sizeof(char)*tamanio_cadena);
		escritos = fread(cabecera->nombre, sizeof(char), tamanio_cadena, *entrada);
		printf("nombre obtenida: @%s@\n", cabecera->nombre);
		if (escritos != tamanio_cadena){
			return 18;
		}
	return EXIT_SUCCESS;
}

Estos son los datos arrojados por consola:

posicion = 27
posicion = 31
posicion = 35
posicion = 43
posicion = 51
i
m
a
g
e
n
.
j
p
g
posicion = 51
se volvio a la posicion: 62
tamanio cadena = 10
nombre obtenida: @����@
nombre del archivo de salida = @����@
DESEMPAQUETAMIENTO EXITOSO

No se porqué posicion queda con el valor 62, ya que en posicion se encuentra el valor 51, Porqué cambia este valor.

Me puse a pensar y solo se me ocurrre que no use bien la funcion fseek();

Pero según man fseek;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
SINOPSIS
       #include <stdio.h>
 
       int fseek( FILE *flujo, long desplto, int origen);
       long ftell( FILE *flujo);
       void rewind( FILE *flujo);
       int fgetpos( FILE *flujo, fpos_t *pos);
       int fsetpos( FILE *flujo, fpos_t *pos);
 
DESCRIPCIÓN
       La función fseek mueve el indicador de posición del fichero correspondiente al flujo de datos apuntado por flujo.  La nueva posición, medida
       en bytes, se obtiene añadiendo desplto bytes a la posición especificada por origen.   Si  origen  es  SEEK_SET,  SEEK_CUR,  o  SEEK_END,  el
       desplazamiento  es relativo al comienzo del fichero, a la posición actual, o al final del fichero, respectivamente. Una llamada exitosa a la
       función fseek limpia el indicador de fin-de-fichero para el flujo y deshace cualquier efecto de la función ungetc(3) en el mismo flujo.
 
       La función ftell obtiene el valor actual del indicador de posición del fichero para el flujo apuntado por flujo.
 
       La función rewind mueve el indicador de posición del fichero para el flujo apuntado por flujo al principio del fichero. Es equivalente a:
 
              (void)fseek(flujo, 0L, SEEK_SET)
 
       salvo en que el indicador de error para el flujo también se limpia (vea clearerr(3)).
 
       Las funciones fgetpos y fsetpos son interfaces alternativas equivalentes a ftell y fseek (con el  origen  puesto  a  SEEK_SET),  poniendo  y
       almacenando  el  valor  actual  del  desplazamiento desde o en el objeto referenciado por pos.  En algunos sistemas no UNIX un objeto fpos_t
       puede ser un objeto complejo y estas rutinas pueden ser la única manera de reposicionar un flujo de texto de forma transportable.
 
VALOR DEVUELTO
       La función rewind no devuelve nada. Cuando acaban bien, fgetpos, fseek, y fsetpos devuelven 0, y ftell devuelve  el  desplazamiento  actual.
       Cuando acaban mal, devuelve -1 y se pone un valor apropiado en la variable global errno.
 
ERRORES
       EBADF  El flujo especificado es tal que no permite el acceso directo.
 
       EINVAL El argumento origen de fseek no era SEEK_SET, SEEK_END, ni SEEK_CUR.
 
       Las  funciones fgetpos, fseek, fsetpos, y ftell pueden fallar también y poner un valor en errno para cualquiera de los errores especificados
       para las rutinas fflush(3), fstat(2), lseek(2), y malloc(3).
 
CONFORME A
       Las funciones fgetpos, fsetpos, fseek, ftell, y rewind siguen el estándar ANSI X3.159-1989 (``C ANSI'').
 
VÉASE TAMBIÉN
       lseek(2), fseeko(3)

Yo la implemente casi como rewind. O almenos eso intenté.
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder

Problema con fseek();

Publicado por Diego (87 intervenciones) el 09/07/2016 18:45:38
LO acabo de solucionar, pero no estoy seguro de porqué no funcionó la primera implementacion que hice.
tenía:
1
2
3
long posicion;
posicion = ftell(*entrada);
fseek(*entrada, 0L, posicion);

y no funcionaba el desplazamiento.

ahora lo cambié por:
1
2
3
size_t posicion;
posicion = ftell(*entrada);
fseek(*entrada, posicion, SEEK_SET);

y funciona correctamente.



Acabo de volver a leer el prototipo de fseek y parece que pide un int como argumento 3 y yo le mandaba un tipo long; puede que ahi radique el error.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Problema con fseek();

Publicado por agustin (179 intervenciones) el 09/07/2016 19:37:41
Tu problema lo solucionaste correctamente pero el fallo no era que fuese un long o un int, el fallo es que el tercer parámetro solo admite unos valores constantes concretos y a saber el valor que le estabas pasando. El segundo es el desplazamiento a partir de la posición indicada por el tercero.
Si haces por ejemplo:
1
fseek(*entrada, 10, SEEK_SET);
Se colocará en la posición inicial + 10.
1
fseek(*entrada, -10, SEEK_END);
Iras a la posición final - 10.
1
fseek(*entrada, 10, SEEK_CUR);
Avanzas 10 posiciones a partir de la posición donde esta.
A ti te estaba dando el error EINVAL.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Problema con fseek();

Publicado por Diego (87 intervenciones) el 09/07/2016 21:31:51
Si, leyendo los errores, me doy cuenta que exige que sea SEEK_SET; SEEK_CUR; SEEK_END

Gracias.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar