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