【问题标题】:Reading a fixed number of chars with << on an istream在 istream 上使用 << 读取固定数量的字符
【发布时间】:2011-06-26 06:36:10
【问题描述】:

我在 C++ 中尝试了一些文件读取策略,结果遇到了这个问题。

ifstream ifsw1("c:\\trys\\str3.txt");
char ifsw1w[3];
do {
    ifsw1 >> ifsw1w;
    if (ifsw1.eof())
        break;
    cout << ifsw1w << flush << endl;
} while (1);
ifsw1.close();

文件的内容是

第一第一第一第二 第二第一第二第二

当我看到输出时,它被打印为

第一第一 第一秒 第二优先

我希望输出类似于:

冷杉 stf 税务局 tfi ......

此外,我看到“secondsecond”尚未打印。我猜最后一次读取已经遇到了 eof 并且 cout 可能没有被执行。但第一种行为是不可理解的。

【问题讨论】:

    标签: c++ iostream ifstream filereader


    【解决方案1】:

    提取运算符没有 ifsw1w 变量大小的概念,并且(默认情况下)将提取字符,直到遇到空格、null 或 eof。这些很可能存储在 ifsw1w 变量之后的内存位置中,如果您定义了其他变量,这将导致错误的错误。

    要获得所需的行为,您应该能够使用

    ifsw1.width(3);
    

    限制要提取的字符数。

    【讨论】:

    • 我不在我的编译器附近,但根据这里的文档,它应该可以工作:cplusplus.com/reference/iostream/istream/operator%3E%3E
    • @irritate 那么十六进制字符串呢?假设我有istringstream s("12AB");,并且我想将其转换为两个unsigned a,b; 变量,这样a 将等于0x12 和b 0xAB。可能这可以通过s &gt;&gt; std::hex &gt;&gt; setw(2) &gt;&gt; a; 然后s &gt;&gt; std::hex &gt;&gt; setw(2) &gt;&gt; b 来实现。但这不起作用,因为istream 没有合适的setw() 操纵器。在这种情况下,s.width(2) 也无济于事。有没有办法限制解析符号的数量?
    • @krokoziabla 我来这里是为了寻找这个问题的答案,很遗憾没有人回答你。
    【解决方案2】:
    1. 几乎不可能安全地使用std::istream&amp; operator&gt;&gt;(std::istream&amp;, char *)——在这方面就像gets——你无法指定缓冲区大小。流只是写入您的缓冲区,结束。 (您上面的示例调用未定义的行为)。要么使用接受std::string 的重载,要么使用std::getline(std::istream&amp;, std::string)

    2. 检查 eof() 不正确。你想要fail()。你真的不关心流是否在文件的末尾,你只关心你没有提取信息。

    对于这样的事情,您最好将整个文件读入一个字符串并从那时起使用字符串操作。您可以使用字符串流来做到这一点:

    #include <string> //For string
    #include <sstream> //For stringstream
    #include <iostream> //As before
    
    std::ifstream myFile(...);
    std::stringstream ss;
    ss << myFile.rdbuf(); //Read the file into the stringstream.
    std::string fileContents = ss.str(); //Now you have a string, no loops!
    

    【讨论】:

      【解决方案3】:

      您正在浪费内存...它的读数超过了您定义的 3 个字符(它的读数直到遇到空格或换行...)。

      逐个字符读取以实现您提到的输出。

      编辑:Irritate 是对的,这也有效(有一些修复并没有得到确切的结果,但这就是精神):

      char ifsw1w[4];
          do{
              ifsw1.width(4);
              ifsw1 >> ifsw1w;
              if(ifsw1.eof()) break;
              cout << ifsw1w << flush << endl;
          }while(1);
          ifsw1.close();
      

      【讨论】:

        【解决方案4】:

        代码具有未定义的行为。当你做这样的事情时:

        char ifsw1w[3];
        
        ifsw1 >> ifsw1w;
        

        operator&gt;&gt; 接收到一个指向缓冲区的指针,但不知道缓冲区的实际大小。因此,它无法知道它应该在两个字符后停止读取(并注意它应该是 2,而不是 3——它需要空间供 '\0' 终止字符串)。

        底线:在您探索读取数据的方法时,最好忽略此代码。你可以从这样的代码中学到的所有东西都是你应该避免的一些事情。但是,通常只遵循一些经验法则比尝试研究所有可能出现的问题更容易。

        1. 使用std::string 读取字符串。
        2. 仅对固定大小的数据使用固定大小的缓冲区。
        3. 当您使用固定缓冲区时,请传递其大小以限制读取的数量。
        4. 当你想读取一个文件中的所有数据时,std::copy可以避免很多错误:

          std::vector<std::string> strings;   
          std::copy(std::istream_iterator<std::string>(myFile),
                    std::istream_iterator<std::string>(),
                    std::back_inserter(strings));
          

        【讨论】:

        • 第三个选项,你说的是width()选项吗?
        • @bsoundra:宽度选项是一个,调用read是另一个。
        【解决方案5】:

        要读取空格,你可以使用“noskipws”,它不会跳过空格。

        ifsw1 >> noskipws >> ifsw1w;
        

        但是如果你只想获取3个字符,我建议你使用get方法:

        ifsw1.get(ifsw1w,3);
        

        【讨论】:

        • ifstream ifsw2("c:\\trys\\str3.txt");字符 ifsw2w[3];做{ ifsw2.get(ifsw2w,2); if(ifsw2.eof()) 中断; cout
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多