【问题标题】:counting the number of lines in a text file计算文本文件中的行数
【发布时间】:2011-03-29 18:22:14
【问题描述】:

我正在从文本文件中读取行,我想知道这是否是一个好方法?我必须编写函数numberoflinesnumber_of_lines variable 减1,因为在while 循环中,它读取的每一行都会将2 加到number_of_lines 变量中。

#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;
}

还有其他更简单更好的方法吗?

【问题讨论】:

  • 您使用的是类 UNIX 系统吗?如果是这样,您是否正在读取带有 DOS 行结尾的文件?如果是这样,一个 DOS 换行符可能会被视为两个 UNIX 换行符。 (我没有测试过;只是一个猜测。)
  • 如果你每行加 2,你不应该把结果除以 2 而不是只减一吗?
  • 你有理由重新发明轮子吗?已经有程序可以做到这一点。试试wc -lunixhelp.ed.ac.uk/CGI/man-cgi?wc
  • @casablanca,对不起,我的意思是,它在开始时会在计数中增加一个 1,我想在这种情况下我可以从 -1 开始计数。 @strager,嗯,我之前添加了换行符,但 getline 不起作用?无论哪种方式,这种方法都适用于 linux 吗?。
  • 我对换行的假设是错误的。我正在阅读您的描述,而不是我应该拥有的代码。有关您正在寻找的解释,请参阅下面的答案。

标签: c++ file gcc text


【解决方案1】:

我认为您的问题是,“为什么我得到的比文件中的多一行?”

想象一个文件:

line 1
line 2
line 3

文件可以这样用 ASCII 表示:

line 1\nline 2\nline 3\n

(其中\n 是字节0x10。)

现在让我们看看每次getline 调用前后会发生什么:

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

现在,您会认为流会标记eof 以指示文件的结尾,对吧?没有!这是因为如果到达文件结束标记"during it's operation"getline 将设置eof。因为getline 在到达\n 时终止,所以不会读取文件结束标记,也不会标记eof。因此,myfile.eof() 返回 false,循环进行另一次迭代:

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

你如何解决这个问题?不要检查eof(),而是查看.peek() 是否返回EOF

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

还可以查看getline的返回值(隐式转换为bool):

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

【讨论】:

  • getline 的返回值在失败时解析为布尔上下文中的false,它试图读取 EOF。
  • @greyfade,这是正确的,但这不会改变我所说的任何内容。不过,我确实在最后添加了一个使用它的示例。
【解决方案2】:

你最后减少计数的技巧就是这样——一个技巧。

一开始就正确编写循环要好得多,因此它不会将最后一行计算两次。

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;
}

我个人认为在这种情况下,C 风格的代码是完全可以接受的:

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;
}

编辑:当然,C++ 也会让你做一些类似的事情:

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 表示 C 风格的代码。我建议进行块读取而不是使用fgetc,因为读取每个字符的函数调用会产生相当高的开销。
  • @casablanca:哎呀——应该是getc,它通常作为宏实现。
  • @qwerty9967:当您从main返回时,文件会自动刷新和关闭。
  • @DavidDoria:我通常会在答案中使用第一个版本。如果我真的关心它的内存使用情况,我可能会写一个使用std::ignore 而不是std::getline 的版本。
  • 为了清理,我建议您在计算完行数后也关闭文件。
【解决方案3】:

在 C 中,如果你实现 count line,它永远不会失败。 是的,如果通常在文件末尾有杂散的 "ENTER KEY",您可以获得额外的一行。

文件可能看起来像这样:

"hello 1
"Hello 2

"

代码如下

#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;
}

【讨论】:

    【解决方案4】:

    带有for循环:

    std::ifstream myFile;
    std::string line;
    int lines;
    
    myFile.open(path);
    
    for(lines = 0; std::getline(myFile,line); lines++);
    
    std::cout << lines << std::endl;
    

    【讨论】:

      猜你喜欢
      • 2016-10-28
      • 1970-01-01
      • 2011-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-28
      • 1970-01-01
      相关资源
      最近更新 更多