【问题标题】:Using getline to read from text file leads to infinite loop when check is eof当检查为 eof 时,使用 getline 从文本文件中读取会导致无限循环
【发布时间】:2013-02-26 23:24:04
【问题描述】:

我正在尝试从文本文件中获取特定行中的一些数据(第 1、第 7、第 13 等 - 所需的数据放在下一个第 6 行)

到目前为止我的代码是这样的:

txtfile = "titles.txt";
ifstream txt(txtfile);
const int buffer_size = 80;
char title_buffer[buffer_size];
const int titleLineDiff = 6;
if (txt.is_open())
{
    while(!txt.eof())
    {
        static int counter = 1;
        txt.getline(title_buffer, buffer_size);
        cout << "Title: \"" << counter << "." << title_buffer << "\"" << endl;
        counter++;
        //seek to the next title...difference is 6 lines
        for(int i = 0; i < titleLineDiff; i++)
            txt.getline(title_buffer, 40);
    }
}

现在,它适用于我创建的这个文件:

testONE
two
three
four 
five
six

testTWO
bla

它打印“testONE”和“testTWO”,但是当我试图打开包含数据的文件时,我得到一个无限循环,输出是

标题:“counter_increasing_number。”

文本文档是从互联网上复制的,这可能是导致阅读问题的原因。

对此我能做些什么?


我已将代码更改为:

while(getline(txt,title_buffer))
{
    static int counter = 1;
    //getline(title_buffer, buffer_size);
    cout << "Title: \"" << counter << "." << title_buffer << "\"" << endl;
    counter++;
    //seek to the next title...difference is 6 lines
    for(int i = 0; i < titleLineDiff; i++)
    {
        getline(txt, title_buffer);
    }
}

它奏效了。

有人可以解释一下为什么第一个不起作用的原因吗?

【问题讨论】:

标签: c++ windows file text


【解决方案1】:

对于初学者,您使用的是getline 的结果,但没有 检查是否成功。 (在第二个版本中,这是 仅适用于内部循环。)

至于为什么第一个版本出错:eof 是否被设置 在最后一次成功读取之后,或在第一次不成功之后, 没有真正指定。当然,还有其他原因 输入可能会失败,但文件结尾除外。成圣的成语 是总是使用getline(和任何其他输入)作为 循环或 if 中的控制表达式。如果表达式是 考虑true,输入成功。有时 在您知道输入失败后检查eof() 很有用; 如果eof() 不正确,那么问题出在其他地方: 硬件错误(bad() 为真)或 格式。

至于为什么您的测试数据和实际数据表现不同, 很难说没有看到两者。一些可能的原因: 不同的行尾约定,可能是一组数据 以不完整的行结尾(如果数据已 使用 Windows 编辑器生成),或比您的行长 缓冲区(在您的第一种情况下)。

【讨论】:

  • 好吧,当eof 被设置时,它肯定会被指定。它在提取到达文件结尾时设置(第 27.7.2.1/3 节)。因此,每当您进行读取时,都会在文件末尾停止。使用.eof() 作为条件的主要问题是,仅仅因为您没有到达文件末尾并不意味着您的提取会成功。这种情况的常见情况是文本文件末尾的额外\n 导致最后一个std::getline 失败。
  • @sftrabbit eof() 首先是内部条件;它在rdbuf()-&gt;sgetc() 返回EOF 时设置,并且传统上,istream 不应再调用streambuf,因此它必须记住这一事实。但是根据正在读取的类型,istream 可能必须向前看;如果在向前看时看到eof,即使读取成功,也会设置eof()。另一方面,如果istream 不必向前看,eof() 可能是假的,即使没有更多的字符要读取。
【解决方案2】:

给你(别忘了阅读 cmets):

示例:

void Example( void )
{
    // DECLARATION
    // *Declare iFile as std::ifstream and attempt to open file: Example.txt
    std::ifstream iFile( "Example.txt" );

    // *If iFile is open, do this:
    if( iFile.is_open( ) )
    {
        // DECLARATION
        // *You could declare strLine as an array of char if you want
        std::string strLine = "";
        unsigned int nLineCount = 0;

        // DO WHATEVER
        // *Read iFile line by line using std::getline
        while( std::getline( iFile, strLine ) )
        {
            // *For the line after every 6th line, we shall print
            // as a title
            // *( nLineCount % 6 ) gives us the remainder of
            // nLineCount / 6 and if the remainder is 0, then
            // do this:
            if( !( nLineCount % 6 ) )
            {
                std::cout << "Title = " << strLine << std::endl;
            }
            // *For every other line, we shall print it normally
            else
            {
                std::cout << strLine << std::endl;
            }

            // *Increase nLineCount by 1;
            nLineCount ++;
        }
        // CLEAN-UP
        // *Done using inFile - so close it
        inFile.close( );
    }
};

已测试:

Title = 1
2
3
4
5
6
Title = 7
8
9
10
11
12
Title = 13
...

Debugging > Paused! Enter any key to continue...

更多... 没有 cmets:

void Example( void ) {
    std::ifstream iFile( "Example.txt" );

    if( iFile.is_open( ) ) {
        std::string strLine = "";
        unsigned int nLineCount = 0;

        while( std::getline( iFile, strLine ) ) {
            if( !( nLineCount % 6 ) )
                std::cout << "Title = " << strLine << std::endl;
            else
                std::cout << strLine << std::endl;
            nLineCount ++;
        }
        iFile.close( );
    }
};

for循环方法,简洁明了:

void Example( void )
{
    std::ifstream iFile( "Example.txt" );

    if( iFile.is_open( ) )
    {
        std::string strLine = "";

        for( unsigned int nLineCount = 0; std::getline( iFile, strLine ); nLineCount ++ ) {
            if( !( nLineCount % 6 ) )
                std::cout << "Title = " << strLine << std::endl;
            else
                std::cout << strLine << std::endl;
        }
        iFile.close( );
    }
};

【讨论】:

    【解决方案3】:

    第二个文件的行数不相等,因为您期望有 7 行,而最后一个块的行数少于此数。这导致您在检查之前超出了 eof。您需要将 eof 条件放在内部 for 循环中。

    编辑: 然后请确保每行不超过 80 个字符。

    【讨论】:

    • 我将 for 循环更改为:int i = 0; while(i &lt; titleLineDiff &amp;&amp; (!txt.eof())){ txt.getline(title_buffer, 80); i++; } 但它不起作用:/
    猜你喜欢
    • 2021-06-27
    • 1970-01-01
    • 2011-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多