Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

STL: лог-файл

505
30 ноября 2007 года
vAC
343 / / 28.02.2006
Как можно реализовать лог-файл (класс, производный от ostream) с дублирующим выводом на экран?
Что-то я уже сделал, но решение мне не нравиться и не всегда работает.
Сделал так:
1. Создал производный класс от filebuf, в нем перегрузил пару виртуальных методов: xsputn, overflow. В конце вызываю реализацию filebuf, а перед этим вывожу на экран через cout:
 
Код:
virtual streamsize xsputn(const char_type *_Ptr, streamsize _Count)
{
  cout.write(_Ptr, _Count);
  return std::filebuf::xsputn(_Ptr, _Count);
}


2. Создал второй класс Log, производный от ostream, в конструкторе инициализирую его буффером Log_buf.

3. Создание лога выглядет так:
 
Код:
Log log("log.txt");


Как можно сделать это по-другому, более красиво? К тому же эта реализация криво работает для чисел, поэтому решил остановиться и спросить совета...
9.7K
01 декабря 2007 года
DaemonDZK
59 / / 08.11.2005
А стоит ли изобретать велосипед, посмотри в сторону boost, там этого добра хватает.
3
01 декабря 2007 года
Green
4.8K / / 20.01.2000
Boost - огромная библиотека.
Если знаешь что-то конкретное из неё для решения проблемы, то почему бы не указать это?
С таким же успехом можно адресовать к google.
9.7K
01 декабря 2007 года
DaemonDZK
59 / / 08.11.2005
Boost.Log. Конкретней некуда :)
3
02 декабря 2007 года
Green
4.8K / / 20.01.2000
Цитата: DaemonDZK
Boost.Log. Конкретней некуда :)


Да нет, можно конкретнее: дай ссылку на конкретную библиотеку из Boost.
Если, кончно, найдешь такую... :D
Ты перед тем, как советы давать, сам то в boost заглядывал?

1.8K
02 декабря 2007 года
k3Eahn
365 / / 19.12.2005
Цитата: vAC
Как можно реализовать лог-файл (класс, производный от ostream) с дублирующим выводом на экран?


Реализовать можно например так:

Потоковый буфер

Код:
template <typename CharType, class TraitsType = std::char_traits<CharType> >
struct basic_composed_streambuf : std::basic_streambuf<CharType, TraitsType>
{
    typedef std::basic_streambuf<CharType, TraitsType> streambuf_type;
    typedef std::set<streambuf_type*> streambuf_container;
    typedef typename streambuf_container::iterator streambuf_iterator;
   
    typedef std::streamsize streamsize;
   
    streambuf_iterator insert(streambuf_type *pStreamBuf)
    {
        streambuf_iterator iter = streamBuffers.insert(pStreamBuf).first;
        return iter;
    }

    void remove(streambuf_iterator iter)
    {
        streamBuffers.erase(iter);
    }

protected:

    virtual int_type overflow(int_type c = TraitsType::eof())
    {
          int_type result =  TraitsType::not_eof(c);

        for (streambuf_iterator current = streamBuffers.begin(), last = streamBuffers.end();
            current != last;
            ++current)
        {
            int_type putResult = (*current)->sputc(c);

            if (putResult == TraitsType::eof() || putResult == 0)
                result = putResult;
        }
     
      return result;
    }
   
    virtual int sync()
    {
        int result = 0;
        for (streambuf_iterator current = streamBuffers.begin(), last = streamBuffers.end();
            current != last;
            ++current)
        {
            if (-1 == (*current)->pubsync())
                result = -1;
        }
        return result;
    }

    virtual void imbue(const std::locale& _loc)
    {
    }

    virtual streamsize xsputn(const CharType *ptr, streamsize count)
    {
        streamsize currentInserted = 0, inserted = 0;
       
        for (streambuf_iterator current = streamBuffers.begin(), last = streamBuffers.end();
            current != last;
            ++current)
        {
            currentInserted = (*current)->sputn(ptr, count);
            inserted = max(inserted, currentInserted);
        }
       
        return inserted;
    }

protected:
    streambuf_container streamBuffers;
};
Сам потоковый класс
Код:
template <typename CharType, class TraitsType = std::char_traits<CharType> >
struct basic_log : std::basic_ostream<CharType, TraitsType>
{
    typedef std::basic_ostream<CharType, TraitsType> base_type;
    typedef basic_composed_streambuf<CharType, TraitsType> composed_streambuf_type;
    typedef std::basic_streambuf<CharType, TraitsType> streambuf_type;
    typedef typename composed_streambuf_type::streambuf_iterator streambuf_id_type;
   
    explicit basic_log(streambuf_type* pStreamBuf = NULL) : base_type(&composedStreamBuf)
    {
        if (pStreamBuf != NULL)
        {
            composedStreamBuf.insert(pStreamBuf);
        }
    }
   
    streambuf_id_type addAnotherBuffer(streambuf_type *pBuffer)
    {
        return composedStreamBuf.insert(pBuffer);
    }

    void removeBuffer(streambuf_id_type id)
    {
        composedStreamBuf.remove(id);
    }

protected:
    composed_streambuf_type composedStreamBuf;
};
Использование
Код:
#include <iostream>
#include <fstream>
#include <windows.h>
#include <streambuf>
#include <set>

...

typedef basic_log<char> logstream;
typedef basic_log<wchar_t> wlogstream;

int main(int argc, char* argv[])
{
    std::filebuf fileBuf;

    if (NULL == fileBuf.open("C:\\log.txt", std::ios_base::app | std::ios_base::out))
        return -1;

    logstream myLog(&fileBuf);
   
    myLog << "GetTickCount = " << GetTickCount() << std::endl;

    logstream::streambuf_id_type buffId =  myLog.addAnotherBuffer(std::cout.rdbuf());

    myLog << "Now also in the console and 5 = " << 5 << std::endl;

    myLog.removeBuffer(buffId);

    myLog << "This one is not gonna get to the console" << std::endl;

    std::cin.get();

    return 0;
}


P.S.: Для буфера, возможно, придётся реализовать ещё кое-какие виртуальные методы.
3
02 декабря 2007 года
Green
4.8K / / 20.01.2000
Цитата: k3Eahn
Реализовать можно например так:


Неплохо.
Вот только set я бы заменил на list, предоставив пользователю самому задуматься об уникальности.
И убрал бы из basic_composed_streambuf::overflow условие if (putResult == TraitsType::eof() || putResult == 0), т.к. вывод в один поток не должен влиять на вывод в другой. Другими словами: если у меня обломиться вывод в консоль, я все же хотел бы иметь соотв. строчку в файле.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог