使用<<读取固定数量的字符在一个istream上

时间:2011-02-13 00:05:16

标签: c++ iostream ifstream filereader

我在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();

该文件的内容为

firstfirst firstsecond
secondfirst secondsecond

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

 firstfirst
firstsecond
secondfirst

我希望输出类似于:

fir
stf
irs
tfi
.....

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

5 个答案:

答案 0 :(得分:7)

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

要获得所需的行为,您应该可以使用

ifsw1.width(3);

限制要提取的字符数。

答案 1 :(得分:2)

你正在摧毁记忆......它的读数超过你定义的3个字符(读数直到满足一个空格或新行......)。

通过char读取char以实现您提到的输出。

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

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

答案 2 :(得分:2)

  1. 几乎不可能安全地使用std::istream& operator>>(std::istream&, char *) - 在这方面就像gets - 你无法指定缓冲区大小。流只是写入缓冲区,结束。 (上面的示例调用未定义的行为)。使用接受std::string的重载,或使用std::getline(std::istream&, std::string)

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

  3. 对于类似这样的事情,你可能最好只是将整个文件读入字符串并使用字符串操作。你可以使用字符串流来做到这一点:

    #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 :(得分:2)

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

char ifsw1w[3];

ifsw1 >> ifsw1w;

operator>>收到缓冲区的指针,但不知道缓冲区的实际大小。因此,它无法知道它应该在两个字符后停止读取(并注意它应该是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));
    

答案 4 :(得分:1)

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

ifsw1 >> noskipws >> ifsw1w;

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

ifsw1.get(ifsw1w,3);