| Ver tema anterior :: Ver siguiente tema | | Autor | Mensaje |
|---|
man_sierra
Registrado: 22 Nov 2007 Mensajes: 7
| Publicado: 03/02/2009 8:51 am | | | Título: Leer Fichero de texto > 55MB |
| Hola a todos, he construido una rutina para leer un fichero de texto, y que cada final de linea '\n' agregue esta a un array, mi problema viene cuando cargo ficheros con mas de 107117 lineas con una ancho de 570 caracteres aproximadamente 55MB, este me avisa que he desbordado la memoria, y por mas que miro el código no encuentro el fallo. La rutina es parte de una librería compilada con GCC en Windows con MinGW.
| Código: | unsigned short int readFileTx(s_File file, char*** vcad, unsigned int* length) { //Variables locales unsigned short int rval = 1; unsigned int i = 0, j = 0; char c;
*vcad = malloc(sizeof (char*)); *(*vcad + 0) = malloc(sizeof (char));
c = fgetc(file.ptr); while (c != EOF) { *(*(*vcad + j) + i) = c; c = fgetc(file.ptr); if (c == '\n') { i++; *(*vcad + j) = realloc(*(*vcad + j), sizeof (char) *(i + 1)); *(*(*vcad + j) + i) = '\0'; printf("\nJ = %d __ I = %d \n", j, i); i = 0; j++; c = fgetc(file.ptr); if (c != EOF) { *vcad = realloc(*vcad, sizeof (char*) * (j + 1)); *(*vcad + j) = malloc(sizeof (char)); } } else { i++; *(*vcad + j) = realloc(*(*vcad + j), sizeof (char) *(i + 1)); } } *length = j; return (rval); }
|
Un saludo y gracias. |
| | Volver arriba | |  | cheroky
Registrado: 22 Sep 2005 Mensajes: 1830 Ubicación: Valladolid (España)
| Publicado: 03/02/2009 10:37 am | | | Título: |
| Viendo a vista de pájaro el código uno de los potenciales errores es utilizar una variable de tipo char para la asignación de fgetc ya que este retorna un carácter empaquetado en un signed int lo que revierte (en la mayoría de los casos) en una conversión a signed char y la comparación a posteriori con EOF es inconsistente.
En cuanto a la rutina: en el caso de ficheros de tamaño no "volatil" es preferible primero comprobar el tamaño del fichero y luego almacenarlo en un array lineal, después la lectura por cualquier otro mecanismo de las lineas via token '\n' se me antoja bastante más eficiente.
Otra tema es la petición de tanta DMA al sistema, se debe verificar si esto es posible, sobre todo desde el codigo vía lectura del puntero retornado por la función de DMA.
*EOF* _________________ A good code is just read it, no comment.
-Alan Cox-
ei?+1=0 |
| | Volver arriba | |  | rir3760

Registrado: 01 Oct 2004 Mensajes: 4836 Ubicación: Mexico
| Publicado: 03/02/2009 4:46 pm | | | Título: |
| | man_sierra escribió: | | he construido una rutina para leer un fichero de texto, y que cada final de linea '\n' agregue esta a un array, mi problema viene cuando cargo ficheros con mas de 107117 lineas con una ancho de 570 caracteres aproximadamente 55MB, este me avisa que he desbordado la memoria, y por mas que miro el código no encuentro el fallo. |
Revisando la funcion esta tiene varias deficiencias:
* La funcion sin importar su proceso (con exito o no) devuelve el valor 1, por el momento seria mejor simplemente eliminar la variable "rval" y eliminar los parentesis en la sentencia "return N;" ya que son innecesarios.
* Debido a que "sizeof(char)" siempre es igual a uno las expresiones "sizeof (char) * (i + 1)" las puedes reducir a "i + 1".
* En ambas ramas de la estrctura de seleccion "if" lo primero que haces es incrementar la variable "i" en una unidad, para evitar codigo duplicado debes mover ese incremento fuera y antes de este (del if).
* Mismo caso con la expresion:
| Código: | *(*vcad + j) = realloc(*(*vcad + j), i + 1); |
* Tambien seria bueno utilizar la variable "i" para contar el numero de filas y "j" para el numero de columnas.
En cuanto a los errores:
* No verificas el valor de retorno de las funciones malloc y realloc (NULL en caso de error).
* Tratas de almacenar lineas de texto sin el caracter '\n' pero esta mal la logica: revisa que hace tu programa si este se alimenta con un archivo que solo contiene lineas en blanco:
'\n' '\n'
...
'\n' {EOF}
* Otro problema son las tres operaciones de lectura "fgetc(file.ptr)" diseminadas dentro del bucle, lo ideal es tener una sola.
La funcion con algunas correcciones pero sin terminar:
| Código: | unsigned short int readFileTx(s_File file, char ***vcad, unsigned *num_lineas) { char **m; unsigned i; unsigned j; int ch; m = malloc(sizeof *m); m[0] = malloc(sizeof *m[0]); i = 0; j = 0; while ((ch = fgetc(file.ptr)) != EOF) if (ch != '\n'){ m[i][j] = ch; j++; m[i] = realloc(m[i], j + 1); }else { m[i][j] = '\0'; i++; j = 0; m = realloc(m, sizeof *m * (i + 1)); m[i] = malloc(1); } if (i == 0 && j == 0){ /* ... archivo vacio ... */ }else if (j == 0){ /* ... eliminar linea extra "m[i]" ... */ }else /* j > 0 */ { /* ... linea malformada ... */ } *vcad = m; *num_lineas = i; return 1; } |
Un saludo _________________ The capacity to learn is a gift; The ability to learn is a skill; The willingness to learn is a choice. -- Rebec of Ginaz |
| | Volver arriba | |  | | man_sierra
Registrado: 22 Nov 2007 Mensajes: 7
| Publicado: 04/02/2009 1:24 am | | | Título: |
| Gracias a ambos, gracias a rir3760 por esa corrección de estilo y de deficiencias lo tendré muy en cuenta. En cuanto a los consejos de cheroky creo los voy a seguir al pie de la letra, primero revisare bien el prototipo de cada función antes de usarla, y desde luego cambiare la lógica de lectura del fichero.
Muchas gracias a ambos. |
| | Volver arriba | |  | man_sierra
Registrado: 22 Nov 2007 Mensajes: 7
| Publicado: 04/02/2009 8:02 am | | | Título: |
| De nuevo gracias ya lo solucione: 1º Abro el fichero y calculo su tamaño
| Código: | unsigned short int openFile(s_File* file) { //Variables locales unsigned short int rval = 1; long int comienzo = 0, final = 0;
file->ptr = fopen(file->path, file->modo); if (file->ptr == NULL) rval = 0; else { fseek(file->ptr, 0L, SEEK_SET); comienzo = ftell(file->ptr); fseek(file->ptr, 0L, SEEK_END); final = ftell(file->ptr); file->size = final - comienzo + 1; rewind(file->ptr); } return (rval); }
|
2º Carga en un array lineal()
| Código: | unsigned short int readFileTx(s_File file, char** vcad) { //Variables locales unsigned short int rval = 1;
*vcad = malloc(file.size); if (*vcad != NULL) fread(*vcad, sizeof (char), (file.size / sizeof (char)), file.ptr); else rval = 0;
return (rval); }
|
3º Después lo organizo en mis estructuras
| Código: | unsigned short int loadVector(char* cadena, sv_strg* vstrg) { // Variables locales unsigned int i = 0, rval = 1; char* sep = malloc(sizeof (char)); char* ptr;
strcpy(sep, "\n"); ptr = strtok(cadena, sep); // Primera llamada => Primer token if (ptr != NULL) { vstrg->iter = malloc(sizeof (s_strg)); (vstrg->iter + i)->value = malloc(sizeof (char) * (strlen(ptr) + 1)); if ((vstrg->iter + i)->value != NULL) { strcpy((vstrg->iter + i)->value, ptr); while ((ptr = strtok(NULL, sep)) != NULL) { i++; vstrg->iter = realloc(vstrg->iter, sizeof (s_strg)*(i + 1)); if (vstrg->iter != NULL) { (vstrg->iter + i)->value = malloc(sizeof (char) * (strlen(ptr) + 1)); if ((vstrg->iter + i)->value != NULL) { (vstrg->iter + i)->size = strlen(ptr); strcpy((vstrg->iter + i)->value, ptr); } else { rval = 0; break; } } else { rval = 0; break; } } } else rval = 0; } vstrg->length = i;
}
|
4º Libero....[/code] |
| | Volver arriba | |  | cheroky
Registrado: 22 Sep 2005 Mensajes: 1830 Ubicación: Valladolid (España)
| Publicado: 04/02/2009 8:39 am | | | Título: |
| Visto en la superficie se adivinan un par de detalles:
En la función readFileTx
| Código: | fread(*vcad, sizeof (char), (file.size / sizeof (char)), file.ptr); | el tamaño del tipo char es absoluto siendo este de un byte, por tanto no hay problema en utlizar si se desea el operador sizeof (precompilador) pero en el caso de aplicar aritmética sobre tipo y operador es una sobrecarga inecesaria. En definitiva en la llamada a fread el "count" es 1 y el "size" es file.size.
En la función loadVector:| Código: | char* sep = malloc(sizeof (char)); | asignas un byte..| Código: | strcpy(sep, "\n"); | luego copias '\n' y '\0' respectivamente en el bloque apuntado por sep, un solo byte, esto provoca un eventual segment fault. No veo ninguna razón para no utlizar directamante un literal de cadena "\n" en las llamadas a strtok.
*EOF* _________________ A good code is just read it, no comment.
-Alan Cox-
ei?+1=0 |
| | Volver arriba | |  | | man_sierra
Registrado: 22 Nov 2007 Mensajes: 7
| Publicado: 06/02/2009 12:56 am | | | Título: |
| Gracias de nuevo, lo corregiré de inmediato. Un saludo. |
| | Volver arriba | |  | | |
| No puede crear mensajes No puede responder temas No puede editar sus mensajes No puede borrar sus mensajes No puede votar en encuestas
|
|
| |