Дата в файле журнала с использованием ofstream

0

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

Должен ли я писать класс журнала и оператор перегрузки << или есть ли другой способ сделать это?

  • 2
    Используйте выделенную библиотеку журналов, например, log4cpp или около того.
  • 1
    Если вы переопределите << , не получите ли вы дату для каждого использования << ?
Показать ещё 2 комментария
Теги:
file
ofstream

1 ответ

1
Лучший ответ

Способ реализации потока, который автоматически добавляет (или удаляет) символы, например, добавляет дату, заключается в создании буфера фильтрующего потока. Вы 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";
}
  • 0
    Спасибо за Ваш ответ. Извините за задержку, я не смотрел свой код в эти выходные. Ваш код отлично работает для ostream но я не знаю, как сделать так, чтобы он работал для ofstream . Я не знаю, как связать sbuf с моим ofstream . Если я пытаюсь просто изменить ostream на ofstream , я получаю сообщение об ошибке, сообщающее, что no matching function for call . Какие-нибудь советы ?
  • 1
    @ Aleph0: вы можете использовать file.std::ostream.rdbuf(&sbuf) для установки потокового буфера в std::ofstream . Тем не менее, я рекомендую не делать этого! Вместо этого вы должны изменить интерфейсы, используя std::ofstream& а вместо этого взять std::ostream& ! Вряд ли когда-либо понадобится использовать специфические методы std::ofstream кроме как в контексте, где создаются эти объекты.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню