Foros del Web » Programación para mayores de 30 ;) » C/C++ »

Pequeño error en ficheros

Estas en el tema de Pequeño error en ficheros en el foro de C/C++ en Foros del Web. Hola. Estoy intentando leer las n últimas líneas de un fichero, para, posteriormente, almacenarlas en otro. Por ejemplo, si mi fichero tiene: Código: hola adiós ...
  #1 (permalink)  
Antiguo 09/05/2012, 10:00
 
Fecha de Ingreso: enero-2012
Mensajes: 68
Antigüedad: 12 años, 3 meses
Puntos: 0
Pequeño error en ficheros

Hola.

Estoy intentando leer las n últimas líneas de un fichero, para, posteriormente, almacenarlas en otro.

Por ejemplo, si mi fichero tiene:

Código:
hola
adiós
duda
ficheros
punteros
estructuras
y meto el número 3 por consola, después de introducir el nombre del fichero, me debería leer:

Cita:
ficheros
punteros
estructuras
Y, sin embargo, me lee:

Código:
os
punteros
estructuras
Mi código es:

Código C:
Ver original
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3.  
  4. typedef struct{
  5.  
  6. int *V;
  7. int lineas;
  8.  
  9. }Estructura;
  10.  
  11. char* InicializarCadena();
  12. Estructura Contar(FILE *fp);
  13. void Almacenar(FILE *fp1,FILE *fp2,Estructura aux,int n);
  14.  
  15. int main (){
  16.  
  17. FILE *fp1;
  18. FILE *fp2;
  19.  
  20. int n;
  21.  
  22. char *fich,c;
  23.  
  24. Estructura aux;
  25.  
  26. printf("Introduzca el nombre del fichero: ");
  27.  
  28. fich=InicializarCadena();
  29.  
  30.  
  31. printf("Introduce un numero: ");
  32. scanf("%d", &n);
  33.  
  34.  * *fp1=fopen(fich, "r");
  35.  * *fp2=fopen("Trabajo.txt", "w");
  36.  
  37.  
  38.  * *if(fp1==NULL){
  39.  * *printf("ERROR");
  40.  * *system("pause");
  41.  * *exit(1);
  42.  * *}
  43.  
  44.  * *aux=Contar(fp1);
  45.  
  46.  
  47.  * *Almacenar(fp1,fp2,aux,n);
  48.  
  49.  free(aux.V);
  50.  free(fich);
  51.  fclose(fp1);
  52.  fclose(fp2);
  53.  
  54. system("pause");
  55. }
  56.  
  57.  
  58. char* InicializarCadena(){
  59.  * int i = 0;
  60.  * char c, *cad;
  61.  
  62.  * cad = (char*) malloc(sizeof(char));
  63.  
  64.  * while((c = getchar())!= '\n'){
  65.  * * *cad[i] = c;
  66.  * * *i++;
  67.  * * *cad = (char*)realloc(cad, (i + 1)*sizeof(char));
  68.  * }
  69.  * cad[i] = '\0';
  70.  
  71.  * return cad;
  72. }
  73.  
  74. Estructura Contar(FILE *fp){
  75.  
  76. int i=0;
  77.  
  78. Estructura aux;
  79.  
  80. char c;
  81.  
  82. aux.lineas=0;
  83.  
  84. aux.V=(int*) malloc(sizeof(int));
  85.  
  86. while(feof(fp)==0){
  87.  
  88. c=fgetc(fp);
  89. i++;
  90.  
  91. if(c=='\n'){
  92. aux.V=(int*) realloc(aux.V,(aux.lineas+1)*sizeof(int));
  93. aux.V[aux.lineas]=i;
  94.  
  95. aux.lineas++;
  96. }
  97. }
  98. aux.lineas++;
  99. return(aux);
  100. }
  101.  
  102. void Almacenar(FILE *fp1,FILE *fp2,Estructura aux,int n){
  103.  
  104. char c;
  105.  
  106. fseek(fp1,aux.V[aux.lineas-n],SEEK_SET);
  107.  
  108.  
  109.  
  110. while(feof(fp1)==0){
  111.  
  112. c = fgetc(fp1);
  113. fputc(c,fp2);
  114. printf("%c", c);
  115.  
  116. }
  117.  
  118. }


¿Qué hago mal?

Muchas gracias.

Saludos.
  #2 (permalink)  
Antiguo 09/05/2012, 12:33
 
Fecha de Ingreso: diciembre-2011
Ubicación: CABA
Mensajes: 433
Antigüedad: 12 años, 3 meses
Puntos: 94
Respuesta: Pequeño error en ficheros

Hola! tratando de ayudart con este problema, vi algo q la verdad no tengo idea de porque pasa. Antes de responderte, primero necesito que ejecutes este codigo
Código C:
Ver original
  1. #include <stdio.h>
  2.  
  3. int main() {
  4.  
  5.     char c;
  6.     int i=0, j=0;
  7.     FILE *fp1=fopen("archivo.txt", "r");
  8.  
  9.  
  10.     while(j<8){
  11.     c=fgetc(fp1);
  12.     i=ftell(fp1);
  13.  
  14.     printf("i:%d %d %c\n",i,c, c);
  15.     j++;
  16.  
  17. }
  18.     system("PAUSE");
  19.     return 0;
  20. }
El archivo.txt es el q vos tenes con: hola, adios........ Vas a ver q cuando lo ejecutas pasa algo(q hasta 1 min no sabia) interesant. Cuando ftell devuelve 4 se imprime 97 y el caracter 'a', hasta aca bien. Pero en el siguiente ciclo vas a notar que ftell no vale 5(como deberia ser) vale 6 y al lado se imprime el 10 y el salto de linea(ENTER)
La verdad nose xq despues de imprimir 'a', ftell devuelve 6 ¿y el 5??? es como que despues de la 'a' de "hola" hay dos "caracteres": uno nose(seria el 5) y el otro es el enter(el 6)

Sabiendo esto, te dejo modificado la parte del codigo q tendrias mal:
Código C:
Ver original
  1. while(feof(fp)==0){
  2.  
  3. c=fgetc(fp);
  4. i++;
  5.  
  6. if(c=='\n'){
  7.             i++;// HAY Q AGREGAR UN INCREMENTO ADICIONAL
  8. aux.V=(int*) realloc(aux.V,(aux.lineas+1)*sizeof(int));
  9. aux.V[aux.lineas]=i;
  10.  
  11. aux.lineas++;
  12. }
  13. }
  14. //aux.lineas++; este incremento estaria demas
  15. return(aux);
  16. }
Agregue un i++ dentro del if, por lo mencionado anteriormente. Comente aux.lineas++; ya q esta demas. Enrealidad no esta demas solo q despues en
Código C:
Ver original
  1. fseek(fp1,aux.V[aux.lineas-n],SEEK_SET);
ademas de restarle n tambien tendrias q restarle 1. Acordate q los arreglos van de 0 a n-1
Otra cosa para arreglar es
Código C:
Ver original
  1. while(feof(fp1)==0){
  2.  
  3. c = fgetc(fp1);
  4. fputc(c,fp2);
  5. printf("%c", c);
  6. }
tendria q ser
Código C:
Ver original
  1. if((c = fgetc(fp1))!=EOF) // tenes q comprar q no sea EOF
  2. fputc(c,fp2);
ya q vas a guardar un caracter demas(basura en fp2). Tenes q poner ese if ya que en cierto modo estas haciendo mal el ciclo while, primero se lee del archivo luego se comprueba q no sea fin de archivo y se vuelve a leer ....ej:
Código C:
Ver original
  1. c=fgetc(fp1); // primero leo del archivo
  2. while(feof(fp1)==0){ // compruebo
  3.  
  4. fputc(c,fp2); // guardo en fp2
  5. printf("%c", c);
  6. c=fgetc(fp1);  // vuelvo a leer
  7. }
Bueno hasta aca llega lo q pude deducir(bastante interesant aunq me qdo un vacio ya q no entendi xq pasa eso), espero q alguien pueda responder el porque de ftell salta de 4 a 6

Saludos

PD: te respondo en este foro tambien xD por si es q alguien me ayuda a mi pregunta
  #3 (permalink)  
Antiguo 09/05/2012, 12:58
 
Fecha de Ingreso: enero-2012
Mensajes: 68
Antigüedad: 12 años, 3 meses
Puntos: 0
Respuesta: Pequeño error en ficheros

¡Muchas gracias! xD

A ver si nos pueden decir por qué pasa eso.

Saludos.
  #4 (permalink)  
Antiguo 09/05/2012, 14:10
 
Fecha de Ingreso: diciembre-2011
Ubicación: Crespo - Entre Rios
Mensajes: 155
Antigüedad: 12 años, 4 meses
Puntos: 25
Respuesta: Pequeño error en ficheros

Código C++:
Ver original
  1. #include <stdio.h>
  2.  
  3. int main() {
  4.     char c;
  5.     int i=0, j=0;
  6.     FILE *fp1=fopen("archivo.txt", "r");
  7.  
  8.     while(j<8){
  9.  
  10.     c=fgetc(fp1);
  11.     i=ftell(fp1);
  12.  
  13.     printf("i:%d j:%d %d %c\n",i,j,c, c);
  14.  
  15.     j++;
  16. }
  17.  
  18.     system("PAUSE");
  19.     return 0;
  20. }

prueben ese codigo y van a ver tambien el valor de la variable j.

segun el razonamiento que segui (puedo estar equivocado), es que cuando fgetc lee el ultimo caracter de la cadena mueve el puntero 1 lugar hacia la derecha, es decir, se encuentra con el caracter de fin de cadena '\0' y lo ignora avanzando hacia el siguiente caracter y lo lee.... entonces, en ese momento, fgetc lee 2 caracteres, ignorando 1, por eso cada vez que se encuentra con el '\0' aumenta en 2 la posicion del puntero dentro del archivo, que es el numero que devuelve ftell...

espero haberme explicado bien :).
saludos
  #5 (permalink)  
Antiguo 09/05/2012, 14:25
 
Fecha de Ingreso: abril-2010
Ubicación: Rosario
Mensajes: 1.850
Antigüedad: 14 años
Puntos: 228
Respuesta: Pequeño error en ficheros

A me funciona bien...no me ocurre el salto que vos decis.
Si lo estan probando en windows, el salto de pagina son dos caracteres, uno es \r y el otro es el \n....

El \r conocido como retorno de carro, lo que hace es volver al principio de la linea...sin hacer un salto de linea....asi que cuando el printf con ese caracter volves al principio. Luego lees el salto de linea pisa la linea que antes habias escrito..... Para que ven como funciona prueben este ejemplo:

for(i=0;i<10;i++) printf("\rNumero de I: %d", i);

Veran que solo se ve una linea. Saludos
  #6 (permalink)  
Antiguo 09/05/2012, 14:33
 
Fecha de Ingreso: enero-2012
Mensajes: 68
Antigüedad: 12 años, 3 meses
Puntos: 0
Respuesta: Pequeño error en ficheros

Muchas gracias a los dos, ya lo he entendido.

Saludos.
  #7 (permalink)  
Antiguo 09/05/2012, 16:56
 
Fecha de Ingreso: diciembre-2011
Ubicación: CABA
Mensajes: 433
Antigüedad: 12 años, 3 meses
Puntos: 94
Respuesta: Pequeño error en ficheros

Hola! gracias x responder a los dos pero aun tengo una pequeña duda.. Con respecto a lo q decis starfix, en primer lugar lo habia pensado de esa manera, pense q fgetc tomaba el '\0' pero despues pense que si toma '\0' deberia imprimir con el formato %d el decimal cero, ya q '\0' equivale a ese numero(sino me equivoco). De todas formas ese caracter nose si se guarda en un archivo

Sam90, probe el programa en linux y es verdad!!! ftell no hace ese salto :) (todo por no qrer abrir el virtualbox y ejecutarlo desde linux)... La duda es, siguiendo la logica de q todo es un caracter, no deberia imprimirse el decimal 13(retorno de carro)??? o es q fgetc no lo toma??
Por lo q decis entiendo esto: supongamos q fgetc toma 'a' de "hola", despues toma '\r' y el printf hace el retorno de carro, luego fgetc toma '\n' y se imprime un salto de linea. Pero esto se debe a q estoy usando %c, pero q pasa si quiero imprimir los caracteres en decimal, no deberia imprimir 97 13 y 10???

En fin suelo compilar mas en linux q windows, es por eso q nunca habia tenido este problema. De todas formas sirvio como aprendizaje sobre windows

Saludos
  #8 (permalink)  
Antiguo 09/05/2012, 18:27
 
Fecha de Ingreso: abril-2010
Ubicación: Rosario
Mensajes: 1.850
Antigüedad: 14 años
Puntos: 228
Respuesta: Pequeño error en ficheros

Esto no es un problema..... Si imprimes en decima te tiene uqe salir un 10 (\r) y despues un 13 \n... proba de casar del prinft la impresion del caracter %c y vas a ver....

El salto de linea se imprime pero se traduce como tal...fijate que hay una linea en blanco.

Linux considera que un salto de linea es solo el \n...de ahi viene el problema que cuando ahcesu n archivo con lin ux cuando lo ves con windows se ve mal..(si lo abris con el block de notas, otro programa un poco mejorado se da cuenta de eso)

Por ultimo un fichero del tipo texto nunca vas a encontrar un '\0'... El \0 es un caracter que se usa para indicar el fin de una cadena.... Pero es solo una convencion dentro del lenguaje. Uno podria redefinir toda las funciones de string.h para que sea otro caracterer.

Saludos
  #9 (permalink)  
Antiguo 09/05/2012, 20:13
 
Fecha de Ingreso: diciembre-2011
Ubicación: CABA
Mensajes: 433
Antigüedad: 12 años, 3 meses
Puntos: 94
Respuesta: Pequeño error en ficheros

Listo ya me quedo clarisismo, ahora lo entendi bien. Y si ya me habia pasado que un archivo creado en linux cuando lo abria en windows se veia mal, pero nunca habia pensado el porque. Muchas gracias

Saludos

Etiquetas: ficheros, int, struct
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 19:19.