2012-07-15 2 views
4

Я хотел бы создать класс адаптера iostream, который позволяет мне изменять данные, записанные или считываемые из потока на лету. Адаптер сам по себе должен быть iostream, чтобы обеспечить истинную прозрачность в отношении стороннего кода.Создание адаптера std :: iostream

Пример для StreamEncoder класса, производного от std::ostream:

// External algorithm, creates large amounts of log data 
int foo(int bar, std::ostream& logOutput); 

int main() 
{ 
    // The target file 
    std::ofstream file("logfile.lzma"); 
    // A StreamEncoder compressing the output via LZMA 
    StreamEncoder lzmaEncoder(file, &encodeLzma); 
    // A StreamEncoder converting the UTF-8 log data to UTF-16 
    StreamEncoder utf16Encoder(lzmaEncoder, &utf8ToUtf16); 

    // Call foo(), but write the log data to an LZMA-compressed UTF-16 file 
    cout << foo(42, utf16Encoder); 
} 

Насколько я знаю, мне нужно создать новый basic_streambuf дериватив и встроить его в basic_ostream подкласса, но это, кажется, довольно сложным.

Есть ли более простой способ сделать это?

+2

Вы видели библиотеку [boost iostreams] (http://www.boost.org/libs/iostreams)? У этого уже есть сжимающие фильтры (хотя не lzma AFAIK), а механика для удобного написания пользовательских фильтров. – Flexo

+0

Я посмотрю. –

+1

Кажется, вам следует изучить концепцию манипуляторов потока.Найдите SO для этого, здесь есть пример http://stackoverflow.com/questions/799599/c-custom-stream-manipulator-that-changes-next-item-on-stream или здесь http://stackoverflow.com/ Вопросы/535444/custom-manipulator-for-c-iostream –

ответ

4

Как ни странно, по крайней мере, поскольку на самом деле все на самом деле предназначено для работы, ничто из этого не должно напрямую затрагивать iostreams и/или streambufs.

Я бы подумал о iostream как о классе состязания. Iostream имеет streambuf, который обеспечивает буферный интерфейс для какого-то внешнего источника/приемника данных. Он также имеет локаль, которая обрабатывает все форматирование. Iostream - это немного больше, чем руководитель детской площадки, который держит этих двух, играющих вместе красиво (так сказать). Поскольку вы имеете дело с форматированием данных, все это (или должно быть) обработано в локали.

Локаль не является монолитной, хотя - она ​​состоит из ряда facet s, каждая из которых посвящена одной части форматирования данных. В этом случае часть, которую вы, вероятно, заботитесь, это фасет codecvt, который используется (почти исключительно) для перевода между внешним и внутренним представлениями данных, которые считываются/записываются в iostreams.

Для лучшего или худшего, однако, язык может содержать только один codecvt facet за раз, а не цепочку из них, как вы созерцаете. Таким образом, то, что вам действительно нужно/нужно, является классом-оболочкой, который предоставляет кодеквт в качестве внешнего интерфейса, но позволяет вам привязать произвольный набор преобразований к данным во время ввода-вывода.

Для преобразования utf-to-utf Boost.locale предоставляет функцию utf_to_utf и код оболочки codecvt, поэтому эта часть преобразования проста и понятна.

Чтобы никто не предполагал, что такие вещи выполняются с помощью ICU, я добавлю, что Boost.Locale в значительной степени является оберткой вокруг ICU, так что это более или менее тот же ответ, но в форме, которая гораздо более дружелюбна к C++ (тогда как ICU сам по себе довольно похож на Java, и все, кроме откровенно враждебного C++).

Другая сторона заключается в том, что запись гранта codecvt добавляет большую сложность к довольно простой задаче. Фильтрующий streambuf (для одного примера), как правило, является лотом проще для записи. Это все еще не так просто, как хотелось бы, но не так плохо, как грань codecvt. Как уже упоминалось в @Flexo, библиотека Boost iostreams уже включает фильтр streambuf, который выполняет сжатие ZIP. Выполнение примерно одинакового с lzma (или lzh, арифметика и т. Д.) Относительно легкое, по крайней мере, предполагая, что у вас есть функции сжатия, которые просты в использовании (вы в основном просто снабжаете их буфером ввода, и они снабжают буфер Результаты).

Смежные вопросы