【问题标题】:Reading a single character from an fstream?从 fstream 中读取单个字符?
【发布时间】:2012-02-28 22:00:30
【问题描述】:

我正在尝试从 stdio 转移到 iostream,这被证明非常困难。我已经掌握了加载文件和关闭文件的基础知识,但我真的不知道流是什么,或者它们是如何工作的。

与此相比,在 stdio 中,一切都相对简单直接。我需要做的是

  1. 从文本文件中读取单个字符。
  2. 根据字符是什么来调用函数。
  3. 重复直到我读完文件中的所有字符。

到目前为止,我所拥有的……不多:

int main()
{
    std::ifstream("sometextfile.txt", std::ios::in);
    // this is SUPPOSED to be the while loop for reading.  I got here and realized I have 
    //no idea how to even read a file
    while()
    {
    }
return 0;
}

我需要知道的是如何获取单个字符以及该字符是如何实际存储的(它是字符串吗?一个 int?一个字符?我可以自己决定如何存储它吗?)

一旦我知道我认为我可以处理剩下的事情。我会将角色存储在适当的容器中,然后使用开关根据该角色的实际情况进行操作。它看起来像这样。

int main()
{
    std::ifstream textFile("sometextfile.txt", std::ios::in);

    while(..able to read?)
    {
        char/int/string readItem;
        //this is where the fstream would get the character and I assume stick it into readItem?
        switch(readItem)
        {
        case 1:
            //dosomething
              break;
        case ' ':
            //dosomething etc etc
              break;
        case '\n':
        }
    }
return 0;
}

请注意,我需要能够检查空格和换行符,希望这是可能的。如果我可以将数字存储在 int 中并将字符存储在 char 中,而不是使用一个通用容器,这也将很方便。如果没有,我可以解决它。

感谢任何可以向我解释流的工作原理以及它们的一切可能的人。

【问题讨论】:

  • 读取单个“字符”的方法是get。如您所见,它也可用于读取多个字符。

标签: c++ file-io iostream fstream


【解决方案1】:

如果您想使用任何算法,您还可以抽象出使用streambuf_iterators 获取单个字符的整个想法:

#include <iterator>
#include <fstream>

int main(){
  typedef std::istreambuf_iterator<char> buf_iter;
  std::fstream file("name");
  for(buf_iter i(file), e; i != e; ++i){
    char c = *i;
  }
}

【讨论】:

  • 在谷歌上搜索了一些关于迭代器的信息后,我认为这是正确的方法,但在我完全理解这里发生了什么之前,我还有很多研究要做。感谢您介绍迭代器。
【解决方案2】:

你也可以使用标准的for_each算法:

#include <iterator>
#include <algorithm>
#include <fstream>

void handleChar(const char& c)
{
    switch (c) {
        case 'a': // do something
            break;
        case 'b': // do something else
            break;
        // etc.
    }
}

int main()
{
    std::ifstream file("file.txt");
    if (file)
        std::for_each(std::istream_iterator<char>(file),
                      std::istream_iterator<char>(),
                      handleChar);
    else {
        // couldn't open the file
    }
}

istream_iterator 跳过空白字符。如果这些在您的文件中有意义,请改用istreambuf_iterator

【讨论】:

  • 请注意,istream_iterator 将为它读取 IIRC 的每个令牌构造一个哨兵,这在单个 char 的情况下可能是相当大的开销。
【解决方案3】:

这已经得到了回答,但无论如何。 您可以使用comma operator 创建一个循环,其行为类似于 for each 循环,该循环遍历整个文件,逐个读取每个字符并在完成时停止。

char c;
while((file.get(c), file.eof()) == false){
    /*Your switch statement with c*/
}

说明: for循环中表达式的第一部分(file.get(c), file.eof()) 将发挥如下作用。首先file.get(c) 被执行,它读取一个字符并将结果存储在c 中。然后,由于逗号运算符,返回值被丢弃并执行 file.eof() ,无论是否已到达文件末尾,它都会返回一个布尔值。然后比较这个值。

旁注: ifstream::get() 总是读取下一个字符。这意味着调用它两次将读取文件中的前两个字符。

【讨论】:

    【解决方案4】:

    fstream::get

    下次遇到类似问题时,请访问cplusplusreference 或类似站点,找到您遇到问题的class 并阅读每种方法的说明。通常,这可以解决问题。谷歌搜索也可以。

    【讨论】:

      【解决方案5】:
      while (textFile.good()) {
        char a;
        textFile.get(a);
         switch(a)
              {
              case 1:
                  //dosomething
                    break;
              case ' ':
                  //dosomething etc etc
                    break;
              case '\n':
          }
      }
      

      【讨论】:

      • 让读取成为您读取循环中的测试 (stackoverflow.com/a/8558959/46642)。
      • 并且不要在循环中声明自动变量
      • @KevinDTimm,我以前也这么想,但是在研究了现代编译器生成的汇编代码后,我发现它们非常聪明,并且在循环之前为这些变量分配内存。
      • @mikithskegg & @AProgrammer - 虽然modern compilers 非常聪明,但我不愿意假设这会发生。此外,我相信我编写的代码应该正确地模仿我想要做的事情(而且我不认为在循环的每次迭代中重新创建一个变量是我想要做的)
      • @KevinDTimm:我建议您专注于大局。最佳算法和代码可读性是重中之重。 “优化前测量”原则适用于其他所有内容。
      猜你喜欢
      • 1970-01-01
      • 2013-04-20
      • 1970-01-01
      • 1970-01-01
      • 2013-05-29
      • 1970-01-01
      • 1970-01-01
      • 2010-09-12
      相关资源
      最近更新 更多