Я новичок в Boost и его пакете iostreams, и нахожу документацию немного тонкой.Надеюсь, кто-то исправит меня.Я пытаюсь преобразовать небольшой фрагмент кода потоков C #, который я написал некоторое время назад, для чтения в сжатом потоке.
byte[] data = new byte[length - 1];
file.Read(data, 0, data.Length);
Stream ret = new ZlibStream(new MemoryStream(data), CompressionMode.Decompress, true);
return ret;
Данные из части файла читаются в буфер памяти, который передает zlibдекомпрессор.Потребитель потока со временем выберет его, а когда он закончится, вызовет Close()
, который в сочетании с сборщиком мусора очистит все ресурсы. Примечание : важное различие заключается в том, что я не пытаюсь распаковать весь файл, только небольшую его часть.Файл уже был найден в некотором внутреннем местоположении, и его длина мала по сравнению с полным размером файла.
Я пытаюсь найти лучший эквивалент этого в C ++-коде с Boost.Пока у меня есть моральный эквивалент вышеприведенному (непроверенному):
char * data = new char[length - 1];
_file.read(data, length - 1);
io::stream_buffer<io::basic_array_source<char> > buffer(data, length - 1);
io::filtering_stream<io::input> * in = new io::filtering_stream<io::input>;
in->push(io::zlib_decompressor());
in->push(buffer);
return in;
Я предполагаю, что мог бы вернуть filtering_stream, завернутый в shared_ptr
, который избавил бы потребителя от необходимости беспокоиться об удалении потока,но у меня также есть этот буфер данных new'd там.В идеале я хотел бы, чтобы потребитель просто вызывал close()
в потоке, и какой-то механизм (например, обратный вызов) очистил бы базовые ресурсы в фильтре.Требование потребителя передать поток явной функции выпуска также приемлемо, но я все еще не совсем уверен, как вернуть базовый буфер данных в первую очередь.
Более чистые альтернативные решения также приветствуются.
Обновление 1
Я попытался свободно воспользоваться комментарием Cat Plus Plus о драйвере с поддержкой std :: vector.Это не совсем то, что я сделал, но это то, что я придумал до сих пор.В следующем коде у меня есть драйвер boost :: shared_array-backed, основанный на примерах драйверов boost.
namespace io = boost::iostreams;
class shared_array_source
{
public:
typedef char char_type;
typedef io::source_tag category;
shared_array_source (boost::shared_array<char> s, std::streamsize n)
: _data(s), _pos(0), _len(n)
{ }
std::streamsize read (char * s, std::streamsize n)
{
std::streamsize amt = _len - _pos;
std::streamsize result = (std::min)(amt, n);
if (result != 0) {
std::copy(_data.get() + _pos, _data.get() + _pos + result, s);
return result;
}
else {
return -1;
}
}
private:
boost::shared_array<char> _data;
std::streamsize _pos;
std::streamsize _len;
};
Тогда у меня есть функция, которая возвращает поток
io::filtering_istream * GetInputStream (...)
{
// ... manipulations on _file, etc.
boost::shared_array<char> data(new char[length - 1]);
_file.read(data.get(), length - 1);
shared_array_source src(data, length - 1);
io::stream<shared_array_source> buffer(src);
io::filtering_istream * in = new io::filtering_istream;
in->push(io::zlib_decompressor());
in->push(buffer);
// Exhibit A
// uint32_t ui;
// rstr->read((char *)&ui, 4);
return in;
}
И в моей основной функции тестовой программы:
int main () {
boost::iostreams::filtering_istream * istr = GetInputStream();
// Exhibit B
uint32_t ui;
rstr->read((char *)&ui, 4);
return 0;
}
Не обращайте внимания на тот факт, что я возвращаю указатель, который никогда не будет освобожден - я сохраняю это как можно более простым.Что происходит, когда я запускаю это?Если я раскомментирую код в Приложении A, я получу правильное считывание в ui
.Но когда я нажимаю на Выставку B, я падаю глубоко, глубоко, глубоко в Boost (иногда).Ну дерьмо, я вышел из сферы видимости и все сломалось, некоторые местные жители должны были разобрать и все испортить.data
находится в shared_array, in
находится в куче, а компрессор построен в соответствии с документами.
Являются ли один из конструкторов или функций надстройки, собирающих ссылку на объект в стеке (а именноio :: stream или filtering_stream's push)?Если это так, я возвращаюсь к исходной точке с неуправляемыми объектами в куче.