C Programa para contar la cantidad de líneas en un archivo -- ampo con file camp codereview Relacionados El problema

C program to count number of lines in a file


8
vote

problema

Español

código muy simple, funciona bien. Estoy interesado principalmente en el método que solía contar líneas. Pensé en usar FETC, pero ni siquiera estoy seguro de si lea el carácter de nueva línea, y creo que también es más lento.

  #include <stdio.h> #include <stdlib.h> #define MAX_SIZE 1000  int main(void){     FILE *in_file;     char line[MAX_SIZE];      in_file = fopen("test", "r");     if(in_file == NULL){         fprintf(stderr, "Unable to open file");         exit(EXIT_FAILURE);     }      int counter = 0; /*Number of lines*/      while(fgets(line, sizeof(line), in_file) != NULL){         counter++;     }      printf("Number of lines in the file is %i", counter);      return 0; }   
Original en ingles

Very simple code, works fine. I'm mainly interested in the method I used to count lines. I thought about using fgetc, but I'm not even sure if it'd read the newline character, and I think it's slower too.

#include <stdio.h> #include <stdlib.h> #define MAX_SIZE 1000  int main(void){     FILE *in_file;     char line[MAX_SIZE];      in_file = fopen("test", "r");     if(in_file == NULL){         fprintf(stderr, "Unable to open file");         exit(EXIT_FAILURE);     }      int counter = 0; /*Number of lines*/      while(fgets(line, sizeof(line), in_file) != NULL){         counter++;     }      printf("Number of lines in the file is %i", counter);      return 0; } 
     

Lista de respuestas

7
 
vote
vote
La mejor respuesta
 

Como dices, funciona bien. Pero puedo nitpick.

La falla principal es que podría obtener un conteo incorrecto si alguna línea es más larga que 999 bytes. (En general, debe esforzarse con el estrés de su código al arrancar el tamaño del búfer a números ridículamente pequeños y verificar si obtiene los mismos resultados).

El rendimiento podría ser mejorado. Dado que fgets() no tiene forma de saber de antemano donde se producen las propiedades, debe leer los contenidos de archivos en un búfer temporal (lo que es invisible para usted), luego copie cada línea en el line < / Código> BUFFER. Dado que solo se preocupa por el conteo ' ' caracteres, puede leer bloques de tamaño fijo para evitar esta copia interna.

Es incómodo leer 1000 bytes a la vez. Usted sería mejor leer trozos que estén alineados con los bloques en el disco. Una mejor opción sería 1024.

Puede usar la función perror()3 para informar por qué falló las operaciones de E / S. Técnicamente, fgets() también podría fallar, por lo que debe verificar si eso.

Es un buen hábito para asegurarse de que su 9988776655544335 esté emparejado con fclose() .

  #include <stdio.h> #include <stdlib.h> #include <string.h>  #define SIZE 1024  int main(void) {     const char filename[] = "test";     FILE *in_file;     char buffer[SIZE + 1], lastchar = ' ';     size_t bytes;     int lines = 0;      if (NULL == (in_file = fopen(filename, "r"))) {         perror(filename);         return EXIT_FAILURE;     }      while ((bytes = fread(buffer, 1, sizeof(buffer) - 1, in_file))) {         lastchar = buffer[bytes - 1];         for (char *c = buffer; (c = memchr(c, ' ', bytes - (c - buffer))); c++) {             lines++;         }     }     if (lastchar != ' ') {         lines++;  /* Count the last line even if it lacks a newline */     }     if (ferror(in_file)) {         perror(filename);         fclose(in_file);         return EXIT_FAILURE;     }      fclose(in_file);     printf("Number of lines in the file is %i ", lines); }   

El for8 Loop es un poco complicado para los principiantes, pero debe ser aceptable para los programadores de C con experiencia. El bucle

  for (char *c = buffer; (c = memchr(c, ' ', bytes - (c - buffer))); c++)   

significa:

  • Buscar la próxima línea nueva, a partir del puntero line0 , en el código 99887766554443311 Bytes que se han leído pero que aún no se han examinado.
  • Si se encuentra una nueva línea, haga line2 Punto a la posición justo después de eso.
  • Si no se encuentra ninguna nueva línea, entonces hemos terminado con este trozo. Intenta leer más entrada entonces.

El conjunto adicional de paréntesis alrededor de line3 es una indicación del compilador y a otros programadores que el 99887766655443314 es de hecho intencional, y se supone que no debe ser line5 .

 

As you say, it works fine. But I can nitpick.

The main flaw is that you could get a wrong count if any line is longer than 999 bytes. (In general, you should stress-test your code by cranking down the buffer size to ridiculously small numbers and checking whether you obtain the same results.)

The performance could be improved. Since fgets() has no way of knowing in advance where the newlines occur, it must read the file contents into a temporary buffer (which is invisible to you), then copy each line into the line buffer. Since only care about counting '\n' characters, you could read fixed-size blocks to avoid this internal copying.

It's awkward to read 1000 bytes at a time. You would be better off reading chunks that are aligned with the blocks on the disk. A better choice would be 1024.

You could use the perror() function to report why I/O operations failed. Technically, fgets() could fail too, so you should check for that.

It's a good habit to ensure that your fopen() is paired with fclose().

#include <stdio.h> #include <stdlib.h> #include <string.h>  #define SIZE 1024  int main(void) {     const char filename[] = "test";     FILE *in_file;     char buffer[SIZE + 1], lastchar = '\n';     size_t bytes;     int lines = 0;      if (NULL == (in_file = fopen(filename, "r"))) {         perror(filename);         return EXIT_FAILURE;     }      while ((bytes = fread(buffer, 1, sizeof(buffer) - 1, in_file))) {         lastchar = buffer[bytes - 1];         for (char *c = buffer; (c = memchr(c, '\n', bytes - (c - buffer))); c++) {             lines++;         }     }     if (lastchar != '\n') {         lines++;  /* Count the last line even if it lacks a newline */     }     if (ferror(in_file)) {         perror(filename);         fclose(in_file);         return EXIT_FAILURE;     }      fclose(in_file);     printf("Number of lines in the file is %i\n", lines); } 

The for loop above is a bit tricky for beginners, but should be acceptable for experienced C programmers. The loop

for (char *c = buffer; (c = memchr(c, '\n', bytes - (c - buffer))); c++) 

means:

  • Search for the next newline, starting from the pointer c, in the remaining bytes - (c - buffer) bytes that have been read but not examined yet.
  • If a newline is found, make c point to the position just after it.
  • If no newline is found, then we're done with this chunk. Try reading more input then.

The extra set of parentheses around c = memchr(xe2x80xa6) is an indication to the compiler and to other programmers that the = is indeed intentional, and is not supposed to be ==.

 
 
     
     
1
 
vote

line6 lee los caracteres de nueva línea. ¡Sería una función bastante inútil si no lo hiciera!

Si realiza una referencia a las versiones del código usando line7 y line8 , muy probable que no vea ninguna diferencia medible. (Haga esto en un archivo de texto bastante grande, por ejemplo, 100 MB, y asegúrese de ejecutar ambos programas varias veces, de lo contrario, los resultados dependerán principalmente de cómo su sistema operativo almacena el archivo en la memoria cuando lo lee, ¡no en su código!) .

Tanto line9 9988776655544332020 leerá el archivo un búfer a la vez, y (con suerte) El tamaño del búfer será el óptimo para el sistema de archivos que está leyendo , no un número adivinado como 1000 o 1024.

De hecho, si enciende la optimización del compilador, es probable que 99887766555443321655443321 sea en línea que generalmente equivale a no más que la expresión única ' '2 , donde ' '3 es un puntero en el búfer de archivos del sistema operativo.

Este tipo de código es a menudo una buena ilustración del principio de que "la optimización prematura sin la evaluación comparativa es la raíz de todo mal". Use las rutinas de la biblioteca que permitan la lógica más simple, no la que usted adivinó podría funcionar más rápido.

 

fgetc() does read newline characters. It would be a pretty useless function if it didn't!

If you benchmark versions of the code using fgetc() and fgets(), quite likely you will see no measurable difference. (Do this on a fairly big text file - e.g. 100Mb, and make sure you run both programs several times, otherwise the results will depend mostly on how your operating system caches the file in memory when you read it, not on your code!).

Both fgets() and fgetc() will read the file one buffer at a time, and (with luck) the buffer size will be the optimum for the file system you are reading, not a guessed number like 1000 or 1024.

In fact, if you switch on compiler optimization, fgetc() is likely to be in-line code which usually amounts to no more than the single expression *bufptr++, where bufptr is a pointer into the operating system's file buffer.

This type of code is often a good illustration of the principle that "premature optimization without benchmarking is the root of all evil". Use the library routines that allows the simplest logic, not the one that you guessed might run fastest.

 
 

Relacionados problema

5  Min y Max de números leen de un archivo  ( Min and max of numbers read from a file ) 
Tuve que crear este programa, y ​​lo hice bien, todo está trabajando y cosas, pero me preguntaba, ¿qué es mejor hacerlo? Quiero un método más eficiente. Asi...

3  Lectura y clasificación de líneas de un archivo  ( Reading and classifying lines from a file ) 
Soy nuevo en C que estoy aprendiendo en la universidad ahora, y no estoy seguro de si lo siguiente se considera en las buenas prácticas o no. Para una asign...

2  Saltando espacios en blanco al leer el archivo  ( Skipping whitespaces when reading file ) 
En la lectura de un archivo, encontré líneas en blanco (incluso en la parte inferior) se bloquean el programa. Para solucionar esto, he agregado el siguiente ...

6  Programa Haskell para cambiar el nombre de las imágenes basadas en datos exif  ( Haskell program to rename images based on exif data ) 
movido originalmente de StackOverFlow , sin saber la existencia de este sitio hermano ... Debe decir que encuentro la programación en Haskell para requer...

2  Clase PHP para el manejo de archivos y la creación  ( Php class for file handling and creation ) 
Esta es una clase muy simple para manejar archivos. Permite acceder, crear y modificar archivos en el sistema o 2 archivos falsos (uno en la memoria y otros...

4  Iterar sobre un archivo varias veces  ( Iterate over a file multiple times ) 
El objetivo del código es imprimir todas las cadenas de un archivo que coinciden con cadenas de otro archivo. Los nombres de ambos archivos son proporcionados...

8  Encuentra el número más grande en una matriz  ( Find the greatest number in an array ) 
El programa lee un archivo .txt que contiene líneas de números. El primero tiene un número N y el segundo tiene números $ N $ a medida que dice la primera l...

2  Fusionar directorios y mantener archivos que tengan más líneas  ( Merging directories and keep files that have more lines ) 
gol Mi objetivo es combinar directorios. Cada vez que un archivo tiene el mismo nombre en dos o más directorios, solo se debe mantener el número más alto ...

9  Entrada de usuario y lectura de contenidos de archivo  ( User input and reading contents of file ) 
Para la divulgación completa: esta es una tarea para mi clase de programación y solo quiero consejos o consejos sobre algunos del código. Detalles de asigna...

6  Clasificación de palabras por frecuencia  ( Sorting words by frequency ) 
Estoy haciendo una tarea simple en óxido después de leer el Libro de óxido : Lea un archivo de texto dividirlo en Whitespace desinfectar palabras elim...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos