Autor
|
Tema: Leer datos de un cierto formato desde un fichero (Leído 4,058 veces)
|
javiepe
Desconectado
Mensajes: 4
|
Buenas,
estoy bastante acostumbrado a programar en Fortran, pero ahora tengo un proyecto en el cual debo programar en C, y aunque tengo en mente cómo hacer el programa, me falla el proceso de lecturas de datos desde un fichero.
Tengo un fichero en el cual hay dos tipos de datos. El primer tipo tiene el siguiente formato:
AAAA-MM-DD E F
(AAAA es año, MM es mes, DD es día, E es un número entero, y F uno decimal)
El segundo tipo es muy parecido:
AAAA-MM-DD F
A mí me interesa leer los números E y F del primer grupo de datos, guardándolos en dos vectores, y leer el número F del segundo grupo de datos, guardándolo en otro vector. Aquí es donde surge mi problema.
Estoy intentando hacer esto utilizando la función fscanf, escribiendo estos dos comando después de delcarar variables y abrir los ficheros:
fscanf (f1, "%d-%d-%d %d %f\n", &ano, &mes, &dia , E1, F1); fscanf (f1, "%d-%d-%d %f\n", &ano, &mes, &dia, F2);
He declarado E1(3000), F1(3000) y F2(3000) asegurándome de que son suficientemente grandes para almacenar todos los números que hay en el fichero.
Haciendo esto, no consigo que se almacenen los números, ni siquiera el año. No sé si la función fscanf se utiliza así o no.
Agradecería cualquier ayuda, ya que tengo el algoritmo básico en mente, pero no puedo aplicarlo por culpa de que no sé cómo leer el fichero.
Muchas gracias.
|
|
« Última modificación: 12 Marzo 2014, 15:33 pm por javiepe »
|
En línea
|
|
|
|
rir3760
Desconectado
Mensajes: 1.639
|
Puedes utilizar la función fscanf siempre y cuando la entrada garantice solo esos dos tipos de linea y nada mas. Primero lees la fecha y a continuación verificas si el resto es uno de los dos casos. Un ejemplo con sscanf: #include <stdio.h> #include <stdlib.h> int main(void) { char *linea[] = { "1970-01-01 1 2.3", "1970-01-01 4.5", "1980-01-01 1 2.3", "1980-01-01 4.5", "1990-01-01 1 2.3", "1990-01-01 4.5", }; size_t num_elem = sizeof linea / sizeof linea[0]; size_t i; unsigned a; unsigned m; unsigned d; int num_ent; double num_pf; int nc; for (i = 0; i < num_elem; i++) if (sscanf(linea [i ], "%u-%u-%u%n", &a , &m , &d , &nc ) == 3){ printf("%u-%02u-%02u: ", a , m , d ); if (sscanf(linea [i ] + nc , "%d%*[ ]%lf", &num_ent , &num_pf ) == 2) printf("%d %.2f\n", num_ent , num_pf ); else if (sscanf(linea [i ] + nc , "%lf", &num_pf ) == 1) else } return EXIT_SUCCESS; }
En tu caso solo tienes que leer el archivo linea por linea con fgets, a continuación la procesas con sscanf. Un saludo
|
|
|
En línea
|
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
|
|
|
leosansan
Desconectado
Mensajes: 1.314
|
Me pasa un detalle para mi curioso. Con esto en el fichero: 1970-01-01 1 1.5 1970-01-01 1.15 1980-01-01 2 2.5 1980-01-01 1.225 1990-01-01 3 3.5 1990-01-01 1.35
la salida es:5: 1 1.5 5: 1 0.15 5: 2 2.5 5: 1 0.225 5: 3 3.5 5: 1 0.35
Es decir, en el código que te pongo a continuación sólo actúa el scanf==5 y lo que hace el muy bandido es, cuando debería actuar para mi criterio el scanf==4, sigue actuando el scanf==5 y lo que hace es coger, en las líneas pares, el decimal y separarlo en la parte entera y la parte decimal y así no deja actuar al scanf==4.
¿Me podrían iluminar a ver qué diablos estoy haciendo fatal?.#include <stdio.h> #include <stdlib.h> #define N 5 int main(){ int i=0,j=0,k=0,aux[3],E[N]; float F1[N],F2[N]; FILE* fichero; fichero = fopen("fecha0.txt", "r"); if ((fichero = fopen("fecha0.txt", "r")) == NULL){ perror("fecha0.txt"); return EXIT_FAILURE; } while (! feof(fichero)){ if (fscanf(fichero,"%d %d %d %d %f ", &aux[0],&aux[1], &aux[2], &E[i], &F1[i])==5){ printf("5: %d %g\n", E[i], F1[i]); i++; } else if (fscanf(fichero,"%d %d %d %f ", &aux[0],&aux[1], &aux[2], &F2[k])==4){ printf("4: %g\n", F2[k]); k++; } else puts("Error"); } for (j=0;j<i;j++) printf ("%3d ",E[j]) ; putchar ('\n'); for (j=0;j<i;j++) printf ("%3g ",F1[j]) ; putchar ('\n'); /*for (j=0;j<k;j++) printf ("%3g ",F2[j]);*/ putchar ('\n'); fclose(fichero); return EXIT_SUCCESS; }
Obviamente el código que cuelga rir3760 funciona, como no podría ser de otra manera al ser suyo, a las mil maravillas. La salida es: 1 2 3 1.5 2.5 3.5 1.15 1.225 1.35
Process returned 0 (0x0)
#include <stdio.h> #include <stdlib.h> #define N 5 int main() { int i=0,j=0,k=0,aux[3],E[N],nc; float F1[N],F2[N]; char linea[81]; FILE* fichero; fichero = fopen("fecha0.txt", "r"); if ((fichero = fopen("fecha0.txt", "r")) == NULL){ perror("fecha0.txt"); return EXIT_FAILURE; } while (! feof(fichero)){ fgets(linea, 80, fichero); if (sscanf(linea, "%d-%d-%d%n", &aux[0], &aux[1], &aux[2], &nc) == 3){ if (sscanf(linea + nc, "%d%*[ ]%f", &E[i], &F1[i]) == 2){ i++; } else if (sscanf(linea + nc, "%f", &F2[k]) == 1){ k++; } else puts("Error"); } } for (j=0;j<i;j++) printf ("%3d ",E[j]) ; putchar ('\n'); for (j=0;j<i;j++) printf ("%3g ",F1[j]) ; putchar ('\n'); for (j=0;j<k;j++) printf ("%3g ",F2[j]) ; putchar ('\n'); fclose(fichero); return EXIT_SUCCESS; }
Gracias de antemano.¡¡¡¡ Saluditos! ..... !!!! REEDITADO:
Lo he solventado de la forma más simple. Ahora la salida es la correcta:5: 1 1.5 4: 1.15 5: 2 2.5 4: 1.225 5: 3 3.5 4: 1.35 1 2 3 1.5 2.5 3.5 1.15 1.225 1.35
Process returned 0 (0x0)
#include <stdio.h> #include <stdlib.h> #define N 5 int main(){ int i=0,j=0,k=0,aux[3],E[N]; float F1[N],F2[N]; FILE* fichero; fichero = fopen("fecha0.txt", "r"); if ((fichero = fopen("fecha0.txt", "r")) == NULL){ perror("fecha0.txt"); return EXIT_FAILURE; } while (! feof(fichero)){ fscanf(fichero,"%d %d %d %d %f ", &aux[0],&aux[1], &aux[2], &E[i], &F1[i]); printf("5: %d %g\n", E[i], F1[i]); i++; fscanf(fichero,"%d %d %d %f ", &aux[0],&aux[1], &aux[2], &F2[k]); printf("4: %g\n", F2[k]); k++; } for (j=0;j<i;j++) printf ("%3d ",E[j]) ; putchar ('\n'); for (j=0;j<i;j++) printf ("%3g ",F1[j]) ; putchar ('\n'); for (j=0;j<k;j++) printf ("%3g ",F2[j]); putchar ('\n'); fclose(fichero); return EXIT_SUCCESS; }
Pero me sigue quedando la duda que planteé.
|
|
« Última modificación: 12 Marzo 2014, 20:43 pm por leosansan »
|
En línea
|
|
|
|
rir3760
Desconectado
Mensajes: 1.639
|
Me pasa un detalle para mi curioso. Con esto en el fichero: ... 1970-01-01 1.15 ... 1980-01-01 1.225 ... 1990-01-01 1.35 la salida es: ... 5: 1 0.15 ... 5: 1 0.225 ... 5: 1 0.35 Es decir, en el código que te pongo a continuación sólo actúa el scanf==5 y lo que hace el muy bandido es, cuando debería actuar para mi criterio el scanf==4, sigue actuando el scanf==5 y lo que hace es coger, en las líneas pares, el decimal y separarlo en la parte entera y la parte decimal y así no deja actuar al scanf==4. ¿Me podrían iluminar a ver qué diablos estoy haciendo fatal?. El problema se debe a que la lectura con "%d %f" siempre sera exitosa ya se trate de un int y un float o bien un float. Tomando como ejemplo la primera linea terminada con 1.15 el especificador "%d" consumirá "1" y "%f" consumirá ".15", eso explica la salida que obtienes en el programa. Para solucionarlo hay que recordar que scanf y familia terminaran tan pronto falle una conversión, esa es la razón por la cual utilizo "%d%*[ ]%lf", ahí el espacio no es opcional, si no se encuentra por lo menos un espacio separando los dos números la función termina y su valor de retorno es uno. Otro error en tu programa es, al utilizar directamente fscanf, el indicador de posición en el archivo se actualizara con la llamada a esa función sin importar su resultado. Un saludo
|
|
|
En línea
|
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
|
|
|
javiepe
Desconectado
Mensajes: 4
|
Muchas gracias a los dos, ya me va quedando todo más claro, pero todavía tengo una duda. Resulta que en el fichero que tengo, además de estas fechas con los números posteriores, hay una línea en la que pone "Observaciones" y otra en la que pone "Predicciones", y me está dando error al implementar vuestros programas. Más concretamente, no sé qué significan esos ==1, ==2.... que ponéis después de las funciones scanf, así que no sé cómo añadir el caso en el que una línea pueda ser "Observaciones" o "Predicciones".
Además, también tengo dudas en cómo almacenar el fichero en el vector "linea" utilizando fgets para poder después procesarlo con sscanf.
Os agradezco de nuevo toda la ayuda, ya os digo que tengo bastante soltura en Fortran, pero que estoy bastante perdido en la forma de leer datos de C.
|
|
|
En línea
|
|
|
|
leosansan
Desconectado
Mensajes: 1.314
|
.............................................................................. no sé qué significan esos ==1, ==2.... que ponéis después de las funciones scanf, ........................................................................................
Representan el número de lecturas que "debe" realizar el sscanf para que este efectivamente haga la lectura. Está referido al número de %d y %f que hay en el sscanf............................................................................... Además, también tengo dudas en cómo almacenar el fichero en el vector "linea" utilizando fgets para poder después procesarlo con sscanf. ........................................................................................
Por ejemplo:........................................... char linea[81]; ............................................ fgets(linea, 80, fichero); ........................................
¡¡¡¡ Saluditos! ..... !!!!
|
|
« Última modificación: 13 Marzo 2014, 14:49 pm por leosansan »
|
En línea
|
|
|
|
javiepe
Desconectado
Mensajes: 4
|
Gracias, ya me ha quedado claro lo de las lecturas del scanf.
Respecto a fgets aún hay un matiz que no me queda claro. En el ejemplo que pones, ¿se guarda el fichero por completo en "char linea"? Es decir, ¿linea(1) sería la primera línea del fichero, linea(2) la segunda, y así sucesivamente? Planteado de otra forma; ¿cuando hacemos fgets lee el fichero?
Saludos!
|
|
|
En línea
|
|
|
|
leosansan
Desconectado
Mensajes: 1.314
|
Gracias, ya me ha quedado claro lo de las lecturas del scanf.
Respecto a fgets aún hay un matiz que no me queda claro. En el ejemplo que pones, ¿se guarda el fichero por completo en "char linea"? Es decir, ¿linea(1) sería la primera línea del fichero, linea(2) la segunda, y así sucesivamente? Planteado de otra forma; ¿cuando hacemos fgets lee el fichero?
Saludos!
El caso que te pongo, con fgets después del while, leería línea a línea el fichero.¡¡¡¡ Saluditos! ..... !!!!
|
|
|
En línea
|
|
|
|
javiepe
Desconectado
Mensajes: 4
|
Entendido! Ya me ha salido por fin! Os agradezco mucho a los dos vuestra ayuda, era muy importante que pudiese resolver esto para poder seguir.
Saludos!
|
|
|
En línea
|
|
|
|
Yoel Alejandro
|
Aunque ya está solucionado, sólo para mostrar una alternativa un poco bizarra pero que se reduce a un único sscanf(). La idea es leer ambos, el entero y el float como flotantes, y de ser necesario convertir el primero a entero. Lo probé y parece funcionar correctamente: #include <stdio.h> #include <stdlib.h> int main(void) { char *linea[] = { "1970-01-01 1 2.3", "1970-01-01 4.5", "1980-01-01 1 2.3", "1980-01-01 4.5", "1990-01-01 1 2.3", "1990-01-01 4.5", }; size_t num_elem = sizeof linea / sizeof linea[0]; size_t i; unsigned a; unsigned m; unsigned d; int num_ent; double num_pf; int n_args; float M, N; for (i = 0; i < num_elem; i++) switch ( n_args = sscanf(linea[i], "%u-%u-%u %f%*[ ]%f", &a, &m, &d, &M, &N) ) { case 5: num_ent = (int)M; num_pf = N; printf("%u-%02u-%02u: %d, %.2f\n", a, m, d, num_ent, num_pf); break; case 4: num_pf = M; printf("%u-%02u-%02u: %.2f\n", a, m, d, num_pf); break; default: puts("Error"); } return EXIT_SUCCESS; }
Salida: 1970-01-01: 1, 2.30 1970-01-01: 4.50 1980-01-01: 1, 2.30 1980-01-01: 4.50 1990-01-01: 1, 2.30 1990-01-01: 4.50
|
|
|
En línea
|
Saludos, Yoel. P.D..- Para mayores dudas, puedes enviarme un mensaje personal (M.P.)
|
|
|
|
Mensajes similares |
|
Asunto |
Iniciado por |
Respuestas |
Vistas |
Último mensaje |
|
|
Guarda basura al leer string desde un fichero.[RESUELTO]
Programación C/C++
|
utz
|
5
|
4,969
|
14 Mayo 2012, 03:36 am
por durasno
|
|
|
En C: Problema al leer String e int desde fichero
Programación C/C++
|
vivianiita13
|
0
|
1,675
|
27 Abril 2015, 14:07 pm
por vivianiita13
|
|
|
Ayuda!!!!!!!!QUIERO LEER LOS DATOS QUE TENGO EN EL FICHERO . Cómo???
Programación C/C++
|
afrocardo
|
0
|
1,810
|
10 Diciembre 2015, 18:40 pm
por afrocardo
|
|
|
Leer datos desde fichero .txt
Programación C/C++
|
alc
|
0
|
2,600
|
29 Enero 2018, 08:54 am
por alc
|
|
|
Map: grabar en fichero // Map: leer desde fichero.
Programación C/C++
|
gastongaston
|
0
|
1,832
|
30 Septiembre 2018, 16:03 pm
por gastongaston
|
|