Перегрузка streambuf
От: paul_shmakov Россия  
Дата: 30.08.02 14:06
Оценка:
Как можно перегрузить streambuf для ofstream для модификации содержимого буфера при фактической записи содержимого в файл? В первую очередь интересует подпечатывание даты в начале новой строки, т.е. после выполнения операции:

s << "Some string\n" << "Another string\n" << flush;

В файле должно оказаться такое содержимое:

[Дата] Some string
[Дата] Another string

Перегрузить оператор << просьба не предлагать — так как один оператор << может записывать в буфер произвольное количество "\n".
Paul Shmakov
Re: Перегрузка streambuf
От: Sergey Россия  
Дата: 30.08.02 14:48
Оценка:
Здравствуйте paul_shmakov, Вы писали:

PS>Как можно перегрузить streambuf для ofstream для модификации содержимого буфера при фактической записи содержимого в файл? В первую очередь интересует подпечатывание даты в начале новой строки, т.е. после выполнения операции:


Во-первых, классы не перегружаются :).

PS> s << "Some string\n" << "Another string\n" << flush;


PS>В файле должно оказаться такое содержимое:


PS>[Дата] Some string

PS>[Дата] Another string

Надо написать свой класс, наследник от basic_streambuf; сначала содрать все из реализации std::basic_filebuf, потом найти в коде все fwrite и поменять их на свою функцию, которая будет сканировать буфер на предмет \n и писать его в файл, дописывая, что тебе над.
Написанный класс подсунуть в basic_ostream:

    myofbuf ofb("filename", std::ios::out | std::ios::binary);
    std::ostream s(&ofb);


Можно для удобства сделать класс my_ofstream, по аналогии с std::basic_ofstream.

PS>Перегрузить оператор << просьба не предлагать — так как один оператор << может записывать в буфер произвольное количество "\n".


И что с того? Анализируй, сколько там ньюлайнов и вклинивайся, где надо.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re: Перегрузка streambuf
От: Павел Кузнецов  
Дата: 30.08.02 14:52
Оценка:
Здравствуйте paul_shmakov, Вы писали:

PS>Как можно перегрузить streambuf для ofstream для модификации содержимого буфера при фактической записи содержимого в файл? В первую очередь интересует подпечатывание даты в начале новой строки, т.е. после выполнения операции:


PS> s << "Some string\n" << "Another string\n" << flush;


PS>В файле должно оказаться такое содержимое:


PS>[Дата] Some string

PS>[Дата] Another string

Надо унаследовать свой класс, скажем LogBuf (;-)), от std::streambuf и подменить его метод overflow, реализовав в нем необходимую семантику. В данном случае эффективнее всего будет скопировать последовательность [pbase(); pptr()) в свою последовательность, вставляя "[Дата] " где нужно. Потом надо переадресовать вызов в std::filebuf::sputn(), дав в качестве аргументов параметры измененной последовательности:

class LogBuf : public std::streambuf
{
public:
  void open( . . . )
  {
    m_file.open( . . . );
  }

  . . .

protected:
  virtual int_type overflow(int_type c = traits::eof())
  {
    // ...
    m_file.sputn(&m_seq[0], m_seq.size());
    return traits::not_eof(c);
  }

private:
  std::vector<char> m_seq;
  std::filebuf      m_file;
};


Кроме того, для полнофункциональной работы твоего буфера надо будет переопределить функции underflow (если буфер предназначен для работы в режиме чтения), seekoff, seekpos (если хочешь, чтобы поток, проинициализированный твоим буфером поддерживал seek), sync и т.д., согласно документации.

Теперь осталось подменить потоку его буфер на твой. Если тебе не надо, чтобы поток был именно std::ofstream, просто передавай в конструктор std::ostream свой буфер, в противном случае надо будет вызывать std::ostream::rdbuf, передавая в качестве аргумента свой LogBuf.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[2]: Перегрузка streambuf
От: Sv2k  
Дата: 30.08.02 16:06
Оценка:
Здравствуйте Павел Кузнецов, Вы писали:

ПК>Здравствуйте paul_shmakov, Вы писали:


PS>>Как можно перегрузить streambuf для ofstream для модификации содержимого буфера при фактической записи содержимого в файл? В первую очередь интересует подпечатывание даты в начале новой строки, т.е. после выполнения операции:


PS>> s << "Some string\n" << "Another string\n" << flush;


PS>>В файле должно оказаться такое содержимое:


PS>>[Дата] Some string

PS>>[Дата] Another string

ПК>Надо унаследовать свой класс, скажем LogBuf (), от std::streambuf и подменить его метод overflow,


ПК>Кроме того, для полнофункциональной работы твоего буфера надо будет переопределить функции underflow (если буфер предназначен для работы в режиме чтения), seekoff, seekpos (если хочешь, чтобы поток, проинициализированный твоим буфером поддерживал seek), sync и т.д., согласно документации.


ПК>Теперь осталось подменить потоку его буфер на твой. Если тебе не надо, чтобы поток был именно std::ofstream, просто передавай в конструктор std::ostream свой буфер, в противном случае надо будет вызывать std::ostream::rdbuf, передавая в качестве аргумента свой LogBuf.


Первоначальное сообщение написал я, просто лень регистрироваться было. Буду разбираться, похоже на выход.

К сожалению, придется переползать на GCC 3.2 (и потерять совместимость с GCC 2.95), так как в старой библиотеке libstdc++ класс ofstream наследуется от fstreambase, в котором есть такие гадости:

class fstreambase : virtual public ios {
    mutable filebuf __my_fb;

public:
    filebuf* rdbuf() const { return &__my_fb; }
    . . .
}


Соответственно, вызывать std::ostream::rdbuf, передавая в качестве аргумента свой LogBuf нереально.
Re[3]: Перегрузка streambuf
От: Павел Кузнецов  
Дата: 30.08.02 16:26
Оценка:
Здравствуйте Sv2k, Вы писали:

S>К сожалению, придется переползать на GCC 3.2 (и потерять совместимость с GCC 2.95), так как в старой библиотеке libstdc++ класс ofstream наследуется от fstreambase, в котором есть такие гадости:


S>
S>class fstreambase : virtual public ios {
S>    mutable filebuf __my_fb;

S>public:
S>    filebuf* rdbuf() const { return &__my_fb; }
S>    . . .
S>}
S>


S>Соответственно, вызывать std::ostream::rdbuf, передавая в качестве аргумента свой LogBuf нереально.


Надо вызывать не std::ofstream::rdbuf, которому, действительно, ничего передать нельзя, и который, действительно, так и должен быть определен, а std::ostream::rdbuf :
LogBuf log_buf ("my_file.log");
std::ofstream file;
static_cast<std::ostream&>(file).rdbuf(&log_buf);
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[4]: Перегрузка streambuf
От: Павел Кузнецов  
Дата: 30.08.02 16:37
Оценка:
Здравствуйте Павел Кузнецов, Вы писали:

ПК>
ПК>LogBuf log_buf ("my_file.log");
ПК>std::ofstream file;
ПК>static_cast<std::ostream&>(file).rdbuf(&log_buf);
ПК>


Да, и еще, вызывать std::ofstream::open() тоже не надо, вместо этого надо вызывать LogBuf::open() у связанного log_buf.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.