¿Cómo puedo procesar un archivo de texto en C por trozos de líneas?

Estoy escribiendo un progtwig en C que procesa un archivo de texto y realiza un seguimiento de cada palabra única (mediante el uso de una estructura que tiene una matriz de caracteres para la palabra y un recuento para el número de ocurrencias) y almacena esta estructura en una estructura de datos . Sin embargo, la asignación incluye: “El archivo txt completo puede ser muy grande y no se puede guardar en la memoria principal. Tenga esto en cuenta en su progtwig”.

Le pregunté después de la clase, y me dijo que leyera el archivo de texto por X líneas a la vez (creo que 20,000 fue su sugerencia?) A la vez, las analizó y actualizó las estructuras, hasta que haya llegado al final del archivo. .

¿Alguien puede ayudar a explicar la mejor manera de hacerlo y decirme qué funciones usar? Soy muy, muy nuevo en C.

(Mi progtwig actual es preciso y correcto para archivos pequeños, solo necesito hacer que se ajuste a archivos enormes).

¡¡Muchas gracias!!

EDITAR:

fp = fopen(argv[w], "r"); if ((fp) == NULL){ fprintf( stderr, "Input file %s cannot be opened.\n", argv[w] ); return 2; } /* other parts of my program here */ char s[MaxWordSize]; while (fscanf(fp,"%s",s) != EOF){ nonAlphabeticDelete(s); // removes non letter characters toLowerCase(s); //converts the string to lowercase //attempts to add to data structure pthread_mutex_lock(&lock); add(words, &q, s); pthread_mutex_unlock(&lock); } 

Esto funciona, solo necesito ajustarlo para pasar X líneas a la vez a través del archivo de texto.

¿Qué hay de getline ()? Aquí un ejemplo de la página del manual http://man7.org/linux/man-pages/man3/getline.3.html

  #define _GNU_SOURCE #include  #include  int main(void) { FILE *stream; char *line = NULL; size_t len = 0; ssize_t read; stream = fopen("/etc/motd", "r"); if (stream == NULL) exit(EXIT_FAILURE); while ((read = getline(&line, &len, stream)) != -1) { printf("Retrieved line of length %zu :\n", read); printf("%s", line); } free(line); fclose(stream); exit(EXIT_SUCCESS); } 

Esto se hace mejor leyendo algunos manuales pero puedo proporcionar una ventaja inicial.

 FILE *fp; fp=fopen("fileToRead.txt", "rb"); if (!fp) { /* handle failure! */ } #define GUESS_FOR_LINE_LENGTH 80 char sentinel = '\0'; while ((sentinel = getc(fp)) != EOF) { ungetc(sentinel, fp); char buffer[20000*GUESS_FOR_LINE_LENGTH]; size_t numRead = fread(buffer, 1, 20000*GUESS_FOR_LINE_LENGTH, fp); if (numRead < 20000*GUESS_FOR_LINE_LENGTH) { /*last run */ } /* now buffer has numRead characters */ size_t lastLine = numRead - 1; while (buffer[lastLine] != '\n') { --lastLine; } /* process up to lastLine */ /* copy the remainder from lastLine to the front */ /* and fill the remainder from the file */ } 

Esto es realmente más como pseudo-código. Como la mayoría tiene un progtwig de trabajo, debe usar esto como una guía.

Primero intenta leer una línea a la vez. Escanee el búfer de línea en busca de límites de palabras y afine la parte de conteo de palabras. Usar una tabla hash para almacenar las palabras y los conteos parece ser un buen enfoque. Haga que la salida sea opcional, para que pueda medir el rendimiento de lectura / análisis / búsqueda.

Luego haga otro progtwig que use el mismo algoritmo para la parte central, pero use mmap para leer partes considerables del archivo y escanear el bloque de memoria. La parte difícil es manejar los límites del bloque.

Compare la salida de ambos progtwigs en un conjunto de archivos enormes, asegúrese de que los conteos sean idénticos. Puedes crear archivos enormes concatenando el mismo archivo muchas veces.

Compara los tiempos también. Utilice la utilidad de línea de comandos de time . Desactive la salida de este punto de referencia para centrarse en la parte de lectura / análisis / análisis.

Compare los horarios con otros progtwigs como wc o cat - > /dev/null . Una vez que obtiene un rendimiento similar, el cuello de botella es la velocidad de lectura del almacenamiento masivo, no queda mucho espacio para mejorar.

EDITAR: mirando su código, tengo estas observaciones:

  • fscanf probablemente no sea la herramienta correcta: al menos debe proteger para el desbordamiento de búfer. ¿Cómo debe manejar foo,bar 1 palabra o 2 palabras?

  • Yo sugeriría usar fgets() o fread y mover un puntero a lo largo del búfer, omitiendo los bytes que no son de palabra, convirtiendo los bytes de la palabra en minúsculas con una indirección a través de una matriz de 256 bytes, evitando copias.

  • Haga que el locking sea opcional a través de una variable de preprocesador. No es necesario si solo se accede a la estructura de words por un solo hilo.

  • ¿Cómo implementaste add ? ¿Qué es q ?