2011-06-12 69 views
1

我是新來提升和它的iostreams包,並找到了一點文件。希望有人會讓我直率。我試圖轉換一小段C#流代碼,我寫了一段時間回讀壓縮流。從一個文件的一部分boost :: iostreams管理資源

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; 

我以爲我能回到裹在shared_ptr這將節省消費者不必擔心刪除流filtering_stream,但我也有那裏的數據緩衝區已經新增了。理想情況下,我希望消費者只需在流上調用close(),並且某些機制(例如回調)將清理過濾器中的基礎資源。要求消費者將流傳遞給顯式釋放函數也是可以接受的,但我仍然不完全確定如何首先獲取底層數據緩衝區。

清潔的替代解決方案也受到歡迎。

更新1

我試圖抓住鬆散由貓加加上約一個std :: vector的支持驅動程序的評論。這不是我所做的,但這是我迄今爲止提出的。在下面的代碼中,我有一個boost :: shared_array支持的驅動程序,基於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在堆上,壓縮機根據文檔構建。

其中一個boost構造函數或函數獲取對堆棧中對象的引用(即io :: stream或filtering_stream的推送)?如果是這樣的話,我可以回到原來的方式,在堆上放置unmananaged對象。

+0

_pos總是等於0否? 你永遠不會爲它分配任何值。 – 2017-05-10 10:07:10

回答

0

最終我不得不放棄嘗試讓Boost iostreams自己清理。當創建一個內部使用boost :: shared_array的自定義數組設備時,解決了我的數據緩衝區留在堆上的問題,事實證明,boost :: iostreams :: filtering_stream/streambuf將一個對象推入鏈中,這意味着它捕獲了我的設備在堆棧上的引用(儘管我可以從源和行爲中推斷出來)。我可以在堆上新增設備,但這隻能讓我回到原點。

我下面的解決方案將流的創建移動到一個很薄的std :: istream包裝器中,然後它可以在boost :: shared_ptr中返回,從而允許在最後一個引用被銷燬時清理所有資源。

template <class Compressor> 
class CompressedIStream : public std::basic_istream<char, std::char_traits<char> > 
{ 
public: 
    CompressedIStream (std::istream& source, std::streamsize count) 
     : _data(new char[count]), _buffer(_data, count), std::basic_istream<char, std::char_traits<char> >(&_filter) 
    { 
     source.read(_data, count); 

     _filter.push(Compressor()); 
     _filter.push(_buffer); 
    } 

    virtual ~CompressedIStream() 
    { 
     delete[] _data; 
    } 

private: 
    char * _data; 
    io::stream_buffer<io::basic_array_source<char> > _buffer; 
    io::filtering_istreambuf _filter; 
}; 

boost::shared_ptr<std::istream> GetInputStream (...) 
{ 
    // ... manipulations on _file, etc. 

    typedef CompressedIStream<io::zlib_decompressor> StreamType; 
    return boost::shared_ptr<StreamType>(new StreamType(_file, length - 1)); 
} 
1

你真的應該避免在堆上分配任何東西。 filtering_stream可以即時解壓縮,因此您無需先更換緩衝區或先讀取文件內容。代碼應該看起來更像是這樣的:

io::filtering_stream stream; 
stream.push(io::zlib_decompressor()); 
stream.push(_file); 

如果你真的需要分配它在堆上,那麼,你應該在一個智能指針把它包裝(但同樣,不讀文件數據首先 - 你冒着緩衝區泄漏的風險,更不用說用這種方式讀大文件可能會非常低效)。

+0

該文件充滿了不同的部門 - 我只想解壓其中的一個。無法保證文件句柄將在流的生命週期之後持續存在。 – 2011-06-12 15:12:27

+0

@jaquadro:您也可以嘗試編寫'std :: vector'-backed設備並使用它來代替手動分配的'char'數組。這應該照顧在適當的時候釋放緩衝區。 – 2011-06-12 15:36:49