【问题标题】:This code is meant to output Hello World. but it outputs 0x22fed8此代码旨在输出 Hello World。但它输出 0x22fed8
【发布时间】:2010-10-07 18:08:46
【问题描述】:

我正在学习 C++ 中的文件处理,但是这里有一个问题。我正在尝试读取文件。 此代码旨在输出 Hello World。但它输出 0x22fed8。

#include <iostream>
#include <fstream>

using namespace std;

    int main()
    {
        fstream file;
        file.open("test.txt",ios::in|ios::out);
        file << "Hello World";
        cout << file;
        file.close();

        return 0;
    }

我做错了什么?

【问题讨论】:

  • 不清楚您要做什么。按照我的阅读方式,您尝试将“hello world”写入both 标准输出(控制台) 到文件test.txt。 (这似乎毫无意义)或者您可能只是想写入文件,在这种情况下 cout 根本不应该存在。或者,也许您正试图从文件中读取数据,并将其打印到标准输出? (在这种情况下,“hello world”字符串不应该在那里)你到底想做什么?

标签: c++


【解决方案1】:

简单的解决方案

正如其他人所指出的,直接将文件打印到流中是行不通的。打印文件内容需要打开 另一个从文件读取的流,或者将流的读取指针重新设置为开头,然后再次读取整个文件(如其他人所示)。

C++ 不会自动执行此操作,但您可以手动执行(此处为打开一个新流):

ifstream ifs("filename");

现在,将文件内容写入另一个流是一个微不足道的补充。不用写文件,只写文件缓冲区:

cout << ifs.rdbuf() << endl;

就是这样!无需循环逐行读取文件。

测试有效流

当我们讨论循环时,请注意以下列方式在循环中读取文件的代码:

while ( !file.eof() )

当出现读取错误时,此代码会产生无限循环。这在很多很多情况下都会发生。考虑例如文件在您阅读时被删除,或者有人移除了包含该文件的 USB 设备,或者该文件的格式错误。所有这些情况都会在这里创建一个无限循环。 从不只在流中测试eof

幸运的是,这个问题的解决方案也很简单。此外,它解释了为什么您的原始代码会产生如此奇怪的结果。事实上,C++ 中的流具有到 bool-like 类型的隐式转换。由于其他地方解释的原因(提示:safe bool idiom),它实际上被转换为void*

这使得测试流是否处于有效的非结束状态以及是否可以安全地读取变得容易。因此,我们可以适当地重新构造循环:

while (file) …

上面的代码依赖于到void* 的转换。任何非null 指针都表示有效流。现在,您的代码中也会发生同样的情况:

cout << file;

由于operator &lt;&lt; 没有合适的重载接受流,C++ 会寻找其他重载并找到指针的重载。所以它隐含地调用这样的东西:

cout << static_cast<void*>(file);

更好的解决方案

我已经在上面解释了一个简单、有效的解决方案。但是,此解决方案需要重新打开文件并再次将其读入内存。这使所需的工作加倍。我们可以通过引入一个像流一样的新类来改善这一点,并且实际上将每个输出一次发送到两个流。这样,您可以同时将数据写入文件和标准流。无需重新读取文件。

这个类本身很简单。以下完整代码演示了一般原理:

#include <iostream>
#include <fstream>

struct sinkpair {
    sinkpair(std::ostream& a, std::ostream& b) : a(a), b(b) { }

    // Forward all ouputs to both streams.
    template <typename T>
    sinkpair& operator <<(T const& value) {
        a << value;
        b << value;
        return *this;
    }

    // Explicit overload needed for manipulators such as `endl`.
    sinkpair& operator <<(std::ostream& (*manip)(std::ostream&)) {
        a << manip;
        b << manip;
        return *this;
    }

private:
    std::ostream& a;
    std::ostream& b;
};

int main() {
    std::ofstream ofs("test.txt");
    sinkpair sp(std::cout, ofs);
    sp << "Hello" << std::endl;
}

【讨论】:

  • file.rdbuf() 可能已被刷新到磁盘。当然,这不是一个微不足道的例子。但如果他要写更多的数据……
  • mree:哇,好点子。我实际上误读了从文件中 reading 的代码。现在,给它写信完全是另一回事。基本上,最好的办法是制作一个带有两个接收器的 iostream(Boost.Iostreams,有人吗?)。
  • +1 这是我认为的答案。尽管在某些情况下测试 .eof 可能很有用(例如,在 "(stream >> foo >> ws) && stream.eof()" 中),但在这种情况下它当然是错误的。
  • 不过,太糟糕了,您本可以解释是什么使“while(file)”工作(运算符 void*()),并在同一句话中解释了他输出的奇怪的十六进制数 :)
  • Weeell,你终于如愿以偿了。
【解决方案2】:

编辑:根据 mrree 的建议。

ifstream fin("file.txt");

if (fin.is_open() == false) {
  // error
}

string line;

while( getline(fin, line) ) {  
  cout << line;
}

【讨论】:

  • 你也可以说:ifstream fin("file.txt")。您可以使用 while(fin){ getline(); 进行测试cout
【解决方案3】:

让我们检查一下这条线

cout << file;

这个输出数字的原因是因为 fstream 的深处是一个文件指针。通过将文件传递给 cout,您实际上是在要求 fstream 的 cout。这将默认为文件的基础句柄的值。

如果你想输出文件的内容,你需要将它读入并逐行输出。

fstream file;
file.open("test.txt",ios::in|ios::out);
file << "Hello World";
file.seekg (0, ios::beg);
while ( !file.eof() ) {
  string temp;
  file >> temp;
  cout << temp << std::eol;
}

file.close();

【讨论】:

  • 你知道while(!file.eof()) 循环总是坏了,对吧? failbitbadbit 必须经过测试才好!!!
  • 实际上我没有 :( 。我对 iostream 的了解充其量是最少的。自从……可能是大学二年级以来,我没有做过有意义的工作。
  • 你可以只循环而不是循环
  • cout cplusplus.com/reference/iostream/ios/operator_voidpt.html
  • file.rdbuf() 可能已被刷新到磁盘。当然,这不是一个微不足道的例子。但如果他要写更多的数据……
【解决方案4】:
#include <iostream>
#include <fstream>

int main(int, char **) 
{
  std::ifstream input("test.txt");
  char c;                                                          
  while (input >> c) {
    std::cout << c;
  }
  return 0;
}

不要包含整个标准命名空间。 如果您想要输入文件流,请使用 ifstream。

你想输出文件的内容,而不是文件。

如果要写入文件,则将其读回并发送到标准输出,

#include <iostream>
#include <fstream>

int main(int, char **)
{
  std::fstream file("test.txt",std::ios::in|std::ios::out);
  file << "Hello" << std::endl;
  file.seekp(std::ios::beg);
  char c;
  while (file >>c) {
      std::cout << c ;
  }
  return 0;
}

Konrad 有最好的答案,但请考虑高级方法:

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

int main(int, char **)
{
  std::fstream file("test.txt",std::ios::in|std::ios::out);
  file << "Hello" << std::endl;
  file.seekp(std::ios::beg);
  std::copy(
      std::istream_iterator<char>(file),
      std::istream_iterator<char>(), 
      std::ostream_iterator<char>(std::cout)
      );
  return 0;
}

【讨论】:

    猜你喜欢
    • 2022-01-25
    • 2021-06-11
    • 2019-05-08
    • 1970-01-01
    • 1970-01-01
    • 2016-05-30
    • 2018-08-13
    • 2016-02-24
    相关资源
    最近更新 更多