Ich lese Zeilen aus einer Textdatei und frage mich, ob dies ein guter Weg ist? Ich musste die Funktion numberoflines
schreiben, um den number_of_lines variable
um eins zu verringern, da in der while-Schleife für jede gelesene Zeile der Variable number_of_lines 2 hinzugefügt wird.
#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;
}
Gibt es einen anderen einfacheren Weg?
Ihr Hack, den Zähler am Ende zu dekrementieren, ist genau das - ein Hack.
Es ist viel besser, Ihre Schleife an erster Stelle richtig zu schreiben, damit die letzte Zeile nicht zweimal gezählt wird.
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;
}
Ich persönlich denke, dass in diesem Fall Code im C-Stil durchaus akzeptabel ist:
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;
}
Edit: Natürlich lassen Sie sich in C++ auch etwas ähnliches machen:
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;
}
Ich denke, Ihre Frage ist: "Warum bekomme ich eine Zeile mehr als in der Datei?"
Stellen Sie sich eine Datei vor:
line 1
line 2
line 3
Die Datei kann in ASCII folgendermaßen dargestellt werden:
line 1\nline 2\nline 3\n
(Wo \n
ist Byte 0x10
.)
Nun sehen wir, was vor und nach jedem Aufruf von getline
passiert:
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: ^
Nun denken Sie, der Stream würde eof
markieren, um das Ende der Datei anzuzeigen, richtig? Nee! Dies liegt daran, dass getline
eof
setzt, wenn die Dateiendemarkierung "während des Betriebs" erreicht wird. Da getline
beendet wird, wenn \n
erreicht wird, wird die Dateiendemarke nicht gelesen und eof
nicht markiert. myfile.eof()
gibt also false zurück und die Schleife durchläuft eine weitere Iteration:
Before 3: line 1\nline 2\nline 3\n
Stream: ^
After 3: line 1\nline 2\nline 3\n
Stream: ^ EOF
Wie reparierst du das? Anstatt nach eof()
zu suchen, prüfen Sie, ob .peek()
EOF
zurückgibt:
while(myfile.peek() != EOF){
getline ...
Sie können auch den Rückgabewert von getline
überprüfen (implizit in bool konvertieren):
while(getline(myfile,line)){
cout<< ...
Wenn Sie in C eine Zählzeile implementieren, schlägt diese niemals fehl. Ja, Sie können eine zusätzliche Zeile erhalten, wenn "ENTER KEY" im Allgemeinen am Ende der Datei verstreut ist.
Die Datei könnte wie folgt aussehen:
"hello 1
"Hello 2
"
Code unten
#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;
}
mit for-Schleife:
std::ifstream myFile;
std::string line;
int lines;
myFile.open(path);
for(lines = 0; std::getline(myFile,line); lines++);
std::cout << lines << std::endl;