Этот код предназначен для вывода Hello World. но он выводит 0x22fed8

Я изучаю обработку файлов на С++, но здесь есть проблема. Я пытаюсь прочитать файл. Этот код предназначен для вывода 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;
    }

Что я делаю неправильно?

Ответ 1

Простое решение

Как указывали другие, прямая печать файла в поток не работает. Для печати содержимого файла потребуется открыть другой поток, который читает из файла, или переустановить указатель чтения потока на начало, а затем снова прочитать весь файл (как показали другие).

С++ не делает это автоматически, но вы можете сделать это вручную (здесь, открыв новый поток):

ifstream ifs("filename");

Теперь запись содержимого файла в другой поток является тривиальным дополнением. Вместо написания файла просто напишите файл-буфер:

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

Это все! Никакой цикл не требуется для чтения файла по строкам.

Тестирование допустимых потоков

Пока мы находимся в курсе циклов, остерегайтесь кода, который читает файлы в цикле следующим образом:

while ( !file.eof() )

Этот код создает бесконечный цикл, когда есть ошибка чтения. Это случается во многих, многих ситуациях. Рассмотрим, например, что файл удаляется во время его чтения или что кто-то удаляет USB-устройство, содержащее файл, или что файл ошибочно отформатирован. Все эти случаи создавали бы цикл бесконечности. Никогда не проверяйте только eof в потоке.

К счастью, решение этой проблемы также довольно просто. Кроме того, это объясняет, почему ваш исходный код дал такой странный результат. На самом деле потоки в С++ имеют неявное преобразование в тип bool. По причинам, объясняемым в другом месте (cue: безопасная идентификация bool), она фактически преобразуется в void*.

Это позволяет легко проверить, находится ли поток в допустимом состоянии, а не на конце, и его можно безопасно читать. Поэтому мы можем переформулировать цикл соответствующим образом:

while (file) …

Приведенный выше код основан на преобразовании в void*. Любой указатель не null указывает действительный поток. Теперь то же самое происходит и в вашем коде:

cout << file;

Поскольку нет соответствующей перегрузки для operator <<, которая берет поток, С++ ищет другие перегрузки и находит перегрузку для указателей. Поэтому он неявно вызывает что-то вроде этого:

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;
}

Ответ 2

РЕДАКТИРОВАТЬ: С подсказками.

ifstream fin("file.txt");

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

string line;

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

Ответ 3

Рассмотрим линию

cout << file;

Причина, по которой выводится число, заключается в том, что глубоко под капотом fstream находится указатель на файл. Передавая файл в cout, вы, по сути, запрашиваете cout из fstream. По умолчанию это будет значение базового дескриптора файла.

Если вы хотите вывести содержимое файла, вам нужно будет прочитать его и вывести его по строкам.

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

Ответ 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;
}