/
Inicio :: Foros

 F.A.Q.F.A.Q.                  Conéctese para revisar sus mensajesConéctese para revisar sus mensajes   

Leer Fichero de texto > 55MB

 
      Índice del Foro elrincondelc.com -> Principiantes C/C++
Ver tema anterior :: Ver siguiente tema  
AutorMensaje
man_sierra



Registrado: 22 Nov 2007
Mensajes: 7

MensajePublicado: 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)

MensajePublicado: 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

MensajePublicado: 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

MensajePublicado: 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

MensajePublicado: 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)

MensajePublicado: 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

MensajePublicado: 06/02/2009 12:56 am
Título:

Gracias de nuevo, lo corregiré de inmediato.
Un saludo.
Volver arriba
      Índice del Foro elrincondelc.com -> Principiantes C/C++
Página 1 de 1Todas las horas están en GMT - 8 Horas

 
No puede crear mensajes
No puede responder temas
No puede editar sus mensajes
No puede borrar sus mensajes
No puede votar en encuestas

(c) ElRincondelC.com

Un proyecto de UrlanHeat.com