【问题标题】:Separating EOF from the character buffer of a Getline将 EOF 从 Getline 的字符缓冲区中分离出来
【发布时间】:2011-12-26 15:53:25
【问题描述】:

我正在使用getline 从输入文件中获取缓冲区中的字符。读完一行后,我遍历所有字符并在地图上进行查找(以进行一些进一步的操作)。 问题是一旦有效字符结束,我的程序就会从输入流中获取 eof 并尝试在地图中查找它。

我尝试检查inputStream.eof()eofbit,看看我何时到达流的末尾,但问题是这两个都在我完成最后的getline() 后立即设置,所以我可以' t 使用它来确定 EOF 字符在输入缓冲区中的位置。

如何识别输入缓冲区中的 EOF 字符并避免在地图中查找它?

while(fileInput) {
fileInput.getline(charBuf,charBufSize);

  for(int i=0; i<=charBufSize ;i++) {
    char* currentChar = &(charBuf[i]);
    // do something with currentChar,
    // which I proceed to do by dereferencing currentChar when I need to access
    // the actual character.
  }
}

【问题讨论】:

  • 您似乎忽略了发布一些显示您遇到的问题的代码。
  • 当我发布代码时,人们会诉诸“你为什么要发布这么多代码”,而我却不这样做:)
  • 没有“eof 字符”之类的东西(除了某些上下文中 Windows 中的 SUB 控制代码),这确实需要一些代码来说明您如何解释该概念。
  • @angry - 我相信是这样,因为您使用 getline 而不检查它是否有效。这就是另一个问题的意义——在 尝试读取之后检查 eof,而不是之前。

标签: c++ file-io eof


【解决方案1】:

C++ 中没有可以检查的 EOF 字符。您需要做的是计算读入的字符数并使用它来了解文件的结束位置。您可以使用istream::gcount() 获取此计数。

您的代码中有几个问题。

我假设你已经声明了

char charBuf[256];
size_t charBufSize = 256;
  1. 第一个问题是您丢弃了第一行输入。逐行读取文件的常用习惯用法是:

    while( fileInput.getLine(charBuf, charBufSize) ) {
      for (...) {  // your for loop is wrong, but I'll get to that in a second
      }
    }
    

    如果您真的想在开始循环之前丢弃第一行,请使用

    fileInput.getLine(charBuf, charBufSize); // this first line will be ignored
    while( fileInput.getLine(charBuf, charBufSize) ) {
      for (...) {  // your for loop is wrong, but I'll get to that in a second
      }
    }
    
  2. charBufSize 包含可以读取的最大数据量,而不是实际读取的数据量。因此,如果您只读取 12 个字符,那么您不仅要对字符 13 执行映射查找,而且还要尝试处理字符 14 到 256。为避免这种情况,请将循环更改为:

    for (int i=0; i < fileInput.gcount(); ++i ) {
      char* currentChar = &(charBuf[i]);
      // do something with currentChar,
      // which I proceed to do by dereferencing currentChar when I need to access
      // the actual character.
    }
    
  3. 您使用的是&lt;= 而不是&lt;。我已经在上面的代码示例中解决了这个问题。

  4. 整个char* currentChar = &amp;(charBuf[i]); 有点不寻常。在我从你的问题中编辑出来的代码中(这样你问的基本输入问题会更清楚),你似乎正确地使用了它,但你似乎可以很容易地声明char currentChar = charBuf[i];进行了微小的更改以避免在您使用它的地方取消引用currentChar

【讨论】:

  • 感谢您的信任投票和信息丰富的回答 :) 我现在明白为什么在所有有效字符结束后循环失败了,因为我循环到缓冲区大小的末尾而不是读取的实际字符数,现在我正在使用 gcount() 似乎可以解决问题(也是
  • @angryInsomniac:循环上方的getline 命令读取文件的第一行,但不处理它。然后进入循环,再次调用getline,读取文件的第二行,然后从那里开始处理。
  • 我认为在复制代码时出现了一些错误:D 实际代码中只有一个 getline,我也在问题中更正了这一点。
【解决方案2】:

charBuf 中没有“EOF 字符”。即使在 EOF 字符作为概念存在的系统上(例如 MS-DOS 和 Windows),istream::getline() 也不会将其存储在 charBuf 中。

贴出的代码中一个明显的错误是循环中的越界访问:i&lt;=charBufSize 应该是i&lt;charBufSize,但要仅处理通过 istream::getline 获得的字符,您应该使用 fileInput.gcount()找出实际写入 charBuf 的字符数:

// assuming char charBuf[charBufSize];
fileInput.getline(charBuf, charBufSize);
for(int i=0; i<fileInput.gcount()-1; i++) // -1 if you don't want to process '\0'
{

或者只使用字符串

// assuming std::string charBuf;
getline(fileInput, charBuf);
for(int i=0; i<charBuf.size(); i++)
{

【讨论】:

    【解决方案3】:

    如果您想逐行阅读,请使用标准的 getline 习惯用法:

    std::string line;
    while (std::getline(inputFile, line))
    {
        // process line
    }
    

    如果您想读取未格式化的(“二进制”)输入,请使用readgcount

    std::array<char, 4096> buf;
    std::streamsize n;
    while (true)
    {
        inputFile.read(buf.data(), buf.size());
    
        if ((n = inputFile.gcount()) == 0) { break; }
    
        // process [buf, buf + n)
    }
    

    【讨论】:

      猜你喜欢
      • 2017-05-14
      • 2019-03-22
      • 1970-01-01
      • 2022-01-02
      • 1970-01-01
      • 1970-01-01
      • 2022-11-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多