2010-08-14 40 views
15

Estoy leyendo líneas fuera del archivo de texto y me pregunto si este es un buen camino a seguir. Tuve que escribir la función numberoflines para disminuir el number_of_lines variable en uno, porque dentro del ciclo while, para cada línea que lee agrega 2 a la variable number_of_lines.contando el número de líneas en un archivo de texto

#include <iostream> 
#include <fstream> 
using namespace std; 

int number_of_lines = 0; 

void numberoflines(); 
int main(){ 
    string line; 
    ifstream myfile("textexample.txt"); 

    if(myfile.is_open()){ 
     while(!myfile.eof()){ 
      getline(myfile,line); 
      cout<< line << endl; 
      number_of_lines++; 
     } 
     myfile.close(); 
    } 
    numberoflines(); 

} 

void numberoflines(){ 
    number_of_lines--; 
    cout<<"number of lines in text file: " << number_of_lines << endl; 
} 

¿Hay alguna otra manera mejor y mejor?

+1

¿Estás en un sistema UNIX? Si es así, ¿estás leyendo un archivo con terminaciones de línea DOS? Si es así, una línea nueva de DOS se puede tratar como dos líneas nuevas de UNIX. (No lo he probado, solo una suposición.) – strager

+0

Si está agregando 2 por línea, ¿no debería dividir el resultado entre 2 en lugar de solo reducirlo en uno? – casablanca

+0

¿Hay alguna razón para reinventar la rueda? Ya hay programas para hacer esto. Pruebe 'wc -l': http://unixhelp.ed.ac.uk/CGI/man-cgi?wc –

Respuesta

46

Su truco de decrementar la cuenta en el fin es exactamente eso, un truco.

Mucho mejor escribir su ciclo correctamente en primer lugar, por lo que no cuenta la última línea dos veces.

int main() { 
    int number_of_lines = 0; 
    std::string line; 
    std::ifstream myfile("textexample.txt"); 

    while (std::getline(myfile, line)) 
     ++number_of_lines; 
    std::cout << "Number of lines in text file: " << number_of_lines; 
    return 0; 
} 

En lo personal, creo que en este caso, el código de estilo C es perfectamente aceptable:

int main() { 
    unsigned int number_of_lines = 0; 
    FILE *infile = fopen("textexample.txt", "r"); 
    int ch; 

    while (EOF != (ch=getc(infile))) 
     if ('\n' == ch) 
      ++number_of_lines; 
    printf("%u\n", number_of_lines); 
    return 0; 
} 

Editar: Por supuesto, C++ también permitirá hacer algo un poco similar:

int main() { 
    std::ifstream myfile("textexample.txt"); 

    // new lines will be skipped unless we stop it from happening:  
    myfile.unsetf(std::ios_base::skipws); 

    // count the newlines with an algorithm specialized for counting: 
    unsigned line_count = std::count(
     std::istream_iterator<char>(myfile), 
     std::istream_iterator<char>(), 
     '\n'); 

    std::cout << "Lines: " << line_count << "\n"; 
    return 0; 
} 
+1

Para que no pase desapercibido: gracias por la corrección @strager. –

+1

+1 para el código de estilo C. Yo sugeriría hacer lecturas de bloque en lugar de usar 'fgetc', ya que una llamada a función para leer cada carácter incurre en una sobrecarga bastante alta. – casablanca

+1

@casablanca: oops - debería haber sido 'getc', que generalmente se implementa como una macro. –

4

Creo que su pregunta es, "¿por qué estoy recibiendo una línea más de la que hay en el archivo?"

Imagínese un archivo:

line 1 
line 2 
line 3 

El archivo se puede representar en formato ASCII como esto: (. Cuando \n es el byte 0x10)

line 1\nline 2\nline 3\n 

Ahora vamos a ver lo que sucede antes y después de cada getline llame al:

Before 1: line 1\nline 2\nline 3\n 
    Stream:^
After 1: line 1\nline 2\nline 3\n 
    Stream:  ^

Before 2: line 1\nline 2\nline 3\n 
    Stream:  ^
After 2: line 1\nline 2\nline 3\n 
    Stream:    ^

Before 2: line 1\nline 2\nline 3\n 
    Stream:    ^
After 2: line 1\nline 2\nline 3\n 
    Stream:      ^

Ahora, piensas que la transmisión marcará eof para indicar el final del archivo, ¿verdad? ¡No! Esto es porque getline establece eof si se alcanza el marcador de fin de archivo "during it's operation". Como getline finaliza cuando alcanza \n, el marcador de fin de archivo no se lee y eof no está marcado. Por lo tanto, myfile.eof() devuelve falso, y el bucle pasa por otra iteración:

Before 3: line 1\nline 2\nline 3\n 
    Stream:      ^
After 3: line 1\nline 2\nline 3\n 
    Stream:      ^EOF 

¿Cómo se puede arreglar esto? En lugar de la comprobación de eof(), ver si .peek() vuelve EOF:

while(myfile.peek() != EOF){ 
    getline ... 

También puede comprobar el valor de retorno de getline (implícitamente fundición a bool):

while(getline(myfile,line)){ 
    cout<< ... 
+0

El valor de retorno de 'getline' se resuelve a' false' en un contexto bool cuando falla; * es decir *, intentó leer más allá del EOF. – greyfade

+0

@greyfade, esto es correcto, pero eso no cambia nada de lo que he dicho. Añadí un ejemplo de usar eso al final, sin embargo. – strager

0

En C si implementa la línea de conteo, nunca fallará. Sí, puede obtener una línea adicional si hay extraviado "ENTER KEY" generalmente al final del archivo.

archivo puede parecer algo como esto:

"hello 1 
"Hello 2 

" 

código de abajo

#include <stdio.h> 
#include <stdlib.h> 
#define FILE_NAME "file1.txt" 

int main() { 

    FILE *fd = NULL; 
    int cnt, ch; 

    fd = fopen(FILE_NAME,"r"); 
    if (fd == NULL) { 
      perror(FILE_NAME); 
      exit(-1); 
    } 

    while(EOF != (ch = fgetc(fd))) { 
    /* 
    * int fgetc(FILE *) returns unsigned char cast to int 
    * Because it has to return EOF or error also. 
    */ 
      if (ch == '\n') 
        ++cnt; 
    } 

    printf("cnt line in %s is %d\n", FILE_NAME, cnt); 

    fclose(fd); 
    return 0; 
} 
Cuestiones relacionadas