Ниже приведен код, который я должен писать каждый раз, когда хочу включить дату в свой файл журнала на данный момент. Я ищу способ не писать мой CurrentDateToString()
каждый раз, когда я хочу что-то написать в своем файле.
ofstream log;
log.open("test.log", ios_base::app);
log << CurrentDateToString() << " | " << "first line" << endl;
log << CurrentDateToString() << " | " << "second line" << endl;
log.close();
И вот моя CurrentDateToString()
:
// convert date to formatted string
string CurrentDateToString()
{
time_t rawtime;
struct tm* timeInfo;
char buffer[80];
time(&rawtime);
timeInfo = localtime(&rawtime);
strftime(buffer, 80, "%Y-%m-%d %I:%M:%S", timeInfo);
string dateString(buffer);
return dateString;
}
Цель здесь состоит в том, чтобы иметь возможность писать эти строки вместо текущих строк, которые я пишу:
log << "first line" << endl;
log << "second line" << endl;
Должен ли я писать класс журнала и оператор перегрузки << или есть ли другой способ сделать это?
Способ реализации потока, который автоматически добавляет (или удаляет) символы, например, добавляет дату, заключается в создании буфера фильтрующего потока. Вы std::streambuf
класс из std::streambuf
который массирует полученные символы в нужную форму, а затем перенаправляет их в базовый буфер потока.
Для использования вами добавления даты в начале строки вы просто наблюдаете символы новой строки, которые будут получены, и установите флаг need_date
если есть need_date
. Когда символ записывается во время установки need_date
, дата записывается и флаг очищается.
Вот как это могло бы выглядеть для вашей даты:
#include <streambuf>
class logbuf
: public std::streambuf {
std::streambuf* sbuf;
bool need_date{true};
using traits_type = std::char_traits<char>;
int overflow(int c) override {
if (c != traits_type::eof()) {
if (need_date) {
std::string date{CurrentDateToString()};
this->sbuf->sputn(date.c_str(), date.size());
need_date = false;
}
if (c == '\n') {
need_date = true;
}
return this->sbuf->sputc(c);
}
else {
return traits_type::not_eof(c);
}
}
int sync() override { return this->sbuf->pubsync(); }
public:
logbuf(std::streambuf* sbuf): sbuf(sbuf) {}
};
Функция overflow()
virtual
функции overflow()
вызывается каждый раз, когда в буфере буфера потока нет места. Поскольку для каждого символа не установлен выходной буфер, производительность может быть улучшена путем добавления переопределения для xsputn()
и/или добавления буферизации). Функция sync()
вызывается каждый раз, когда поток очищается. Поскольку ничто не буферизовано, запрос на флеш просто перенаправляется в базовый буфер потока.
Ниже приведена простая демонстрация, использующая этот буфер потока. Создание подходящего базового буфера потока, например std::filebuf
и std::ostream
может быть упаковано в класс, полученный из std::ostream
.
#include <iostream>
int main()
{
logbuf sbuf(std::cout.rdbuf());
std::ostream logout(&sbuf);
logout << "hello\nwordl\n";
logout << "\n";
logout << "goodbye\n";
}
ostream
но я не знаю, как сделать так, чтобы он работал для ofstream
. Я не знаю, как связать sbuf
с моим ofstream
. Если я пытаюсь просто изменить ostream
на ofstream
, я получаю сообщение об ошибке, сообщающее, что no matching function for call
. Какие-нибудь советы ?
file.std::ostream.rdbuf(&sbuf)
для установки потокового буфера в std::ofstream
. Тем не менее, я рекомендую не делать этого! Вместо этого вы должны изменить интерфейсы, используя std::ofstream&
а вместо этого взять std::ostream&
! Вряд ли когда-либо понадобится использовать специфические методы std::ofstream
кроме как в контексте, где создаются эти объекты.
<<
, не получите ли вы дату для каждого использования<<
?