Подтвердить что ты не робот

Пользовательский поток

Мне нужно руководство или указатели, которые понимают, как реализовать пользовательский поток. Мои требования:

  • Класс с '< < оператора для нескольких типов данных.
  • Цель состоит в отправке вывода в базу данных. Каждая "строка" должна перейти к отдельной записи.
  • В каждой записи наиболее важным полем будет текст (или blob), но некоторые другие поля, такие как время и т.д., могут быть в основном выведены автоматически. Буферизация
  • важна, поскольку я не хочу обращаться к базе данных для каждой записи.

Во-первых, стоит ли это извлекать из ostream? Что я получаю от вывода из потока? Что делать, если мой класс просто реализует несколько методов operator<< (включая некоторые пользовательские типы данных). Какую функциональность я получаю из потока?

Предполагая, что я хочу, это класс, полученный из ostream, мне нужно некоторое руководство, понимающее взаимосвязь между классами ostream и streambuf. Какой из них мне нужно реализовать? Если посмотреть на некоторые образцы, кажется, что мне вообще не нужно выводить из ostream, а просто дать конструктору ostream собственный streambuf. Это правда? что канонический подход?

Какие виртуальные функции в пользовательском streambuf мне нужно реализовать? Я видел несколько примеров (включая этот сайт: здесь и здесь и еще несколько), некоторые переопределяют метод sync и другие переопределяют метод overflow. Какой я должен переопределить? Кроме того, глядя на источники stringbuf и filebuf (Visual Studio или GCC), оба эти класса буферов реализуют множество методов streambuf.

Если требуется собственный класс, созданный из streambuf, будет ли какая-либо выгода, получаемая из stringbuf (или любого другого класса), а не непосредственно из streambuf?

Что касается "строк". Я бы хотел, по крайней мере, когда мои пользователи класса с использованием манипулятора 'endl' стали новой строкой (т.е. Записью в базе данных). Может быть - зависит от усилий - каждый символ \n 'следует рассматривать как новую запись. Кто из моих пользовательских ostream и/или streambuf получает уведомление для каждого?

4b9b3361

Ответ 1

Пользовательское назначение для ostream означает реализацию вашего собственного ostreambuf. Если вы хотите, чтобы ваш streambuf фактически буферизовался (т.е. Не подключался к базе данных после каждого символа), самый простой способ сделать это - создать класс, наследующий от std::stringbuf. Функция только, которую вам нужно переопределить, это метод sync(), который вызывается всякий раз, когда поток очищается.

class MyBuf : public std::stringbuf
{
public:
    virtual int sync() {
        // add this->str() to database here
        // (optionally clear buffer afterwards)
    }
};

Затем вы можете создать std::ostream с помощью своего буфера:

MyBuf buff;
std::ostream stream(&buf)

Большинство людей советовали не перенаправлять поток в базу данных, но они проигнорировали мое описание, что в базе данных в основном есть одно поле blob, где весь текст будет. В редких случаях я могу отправить данные в другое поле. Этому могут способствовать пользовательские атрибуты, понятные моему потоку. Например:

MyStream << "Some text " << process_id(1234) << "more text" << std::flush

В приведенном выше коде будет создана запись в базе данных с помощью:

blob: 'Some text more text'
process_id: 1234

process_id() - метод, возвращающий структуру ProcessID. Затем, в реализации моего ostream, у меня есть operator<<(ProcessID const& pid), который хранит идентификатор процесса до тех пор, пока он не будет написан. Отлично работает!

Ответ 2

Самый простой способ - наследовать std::streambuf и переопределить только два метода:

  • std::streamsize xsputn(const char_type* s, std::streamsize n) - добавить данный буфер с размером, указанным в вашем внутреннем буфере, std::string например;
  • int_type overflow(int_type c) - добавить один char в свой внутренний буфер.

Ваш streambuf может быть сконструирован из всего, что вам нужно (например, для подключения к базе данных). После добавления чего-либо во внутренний буфер вы можете попытаться разбить его на строки и нажать что-нибудь в БД (или просто буферизовать SQL-запросы для выполнения позже).

Чтобы использовать его: просто прикрепите streambuf к любому std::ostream с помощью конструктора.

Simple! Я сделал что-то подобное для вывода строк в syslog - все работает отлично с любым пользовательским operator<< для пользовательских классов.

Ответ 3

my2c - Я думаю, что вы занимаетесь этим неправильно. Поток может показаться приятной идеей, но вам понадобится способ указать конец строки тоже (а потом что, если кто-то забудет?) Я бы предложил что-то вроде того, как работают Java PreparedStatements и партии, так как в предоставлении набора методов, которые принимают типы и индекс столбца, затем "пакетный" метод, который явно дает понять, что вы действительно выполняете эту строку, а затем выполняете, чтобы вставить пакет.

Любая операция, основанная на потоке, будет полагаться на тип (обычно), чтобы указать, какой столбец заполняется, но что, если у вас есть два ints? IMO, как пользователь, не кажется естественным способом вставки записей в базу данных...

Ответ 4

Чтобы добавить новый источник или назначение ввода/вывода символов в механизм iostreams, вы должны создать новый класс streambuf. Задача классов буфера потока - связываться с "внешним устройством", которое будет хранить символы и предоставлять средства буферизации.

Проблема с использованием iostreams для связи с вашей базой данных заключается в том, что таблица базы данных не соответствует концепции последовательности символов. Немного похоже на толкание круглого штифта в квадратное отверстие. A streambuf работает только с символами. Это единственное, что когда-либо было представлено ему. Это означает, что streambuf должен проанализировать переданный ему поток символов, чтобы найти разделители полей и записей. Если вы решите пойти по этому маршруту, я предскажу, что вы в конце концов напишите конвертер CSV-to-SQL в своем streambuf, чтобы заставить его работать.

Вероятно, вам будет лучше, только добавив несколько перегрузок operator<< к вашим классам. Вы можете посмотреть на рамки Qt для идей здесь. Они также имеют возможность использовать operator<< для добавления элементов в коллекции и т.д.