2016-05-19 21 views
4

配列をファイルに書き出し、圧縮します。boostのiostreamで圧縮ファイルを読み書きする

後で、私はそのファイルから配列を読み込み、解凍します。

ブーストのIostreamsは良い方法のように思えるので、次のコードを作成しました。残念なことに、出力と入力データは最終的には比較されません。しかし、これは非常に近いです:

Output   Input 
0.8401877284 0.8401880264 
0.3943829238 0.3943830132 
0.7830992341 0.7830989957 
0.7984400392 0.7984399796 
0.9116473794 0.9116470218 
0.1975513697 0.1975509971 
0.3352227509 0.3352229893 

これは、各フロートの最下位バイトが変更されていることを示唆しています。しかし圧縮は無損失でなければならないので、これは予期しないか、望ましくない。何がありますか?

//Compile with: g++ test.cpp --std=c++11 -lz -lboost_iostreams 
#include <fstream> 
#include <iostream> 
#include <boost/iostreams/filtering_stream.hpp> 
#include <boost/iostreams/filter/zlib.hpp> 
#include <cstdlib> 
#include <vector> 
#include <iomanip> 

int main() 
{ 
    using namespace std; 
    using namespace boost::iostreams; 

    const int NUM = 10000; 

    std::vector<float> data_out; 
    std::vector<float> data_in; 
    data_in.resize(NUM); 
    for(float i=0;i<NUM;i++) 
     data_out.push_back(rand()/(float)RAND_MAX); 

    { 
     ofstream file("/z/hello.z", ios_base::out | ios_base::binary); 
     filtering_ostream out; 
     out.push(zlib_compressor()); 
     out.push(file); 

     for(const auto d: data_out) 
     out<<d; 
    } 

    { 
     ifstream file_in("hello.z", ios_base::in | ios_base::binary); 
     filtering_istream in; 
     in.push(zlib_decompressor()); 
     in.push(file_in); 

     for(float i=0;i<NUM;i++) 
     in>>data_in[i]; 
    } 

    bool all_good=true; 
    for(int i=0;i<NUM;i++){ 
     cout<<std::setprecision(10)<<data_out[i]<<" "<<data_in[i]<<endl; 
     all_good &= (data_out[i]==data_in[i]); 
    } 

    cout<<"Good? "<<(int)all_good<<endl; 
} 

そして、はい、私は非常に多く、むしろ一度に全体のベクトルブロックを押したり引っ張っよりも、私のやり方では、ストリーム演算子を使用することを好みます。

+0

サンプルから圧縮を外しても問題が発生しますか? –

+1

はい、それは、ちょうどそれを試みました。浮動小数点数を文字列としてファイルに出力しています。セパレータもありません。 1より小さい値を保存することができれば、遠隔的に賢明なものを手に入れることができます。 –

+0

私は区切り文字が圧縮/解凍に必要ではないはずがないと思います。浮動小数点数が内部のバイトバッファにプッシュされ、圧縮に十分なデータが利用できるようになると想像します。圧縮解除も同様に機能します。データは十分な情報が利用可能になると、内部バッファに読み込まれ、そこから引き出されます。 – Richard

答えて

1

DanMašekがtheir answerで指摘したように、私が使用していた<<ストリーム演算子は、圧縮前に浮動小数点データをテキスト表現に変換していました。何らかの理由で、私はこれを期待していませんでした。

これを回避する方法の1つはシリアライゼーションライブラリを使用することですが、overheadに加えて追加の依存関係が導入されます。

したがって、浮動小数点データの場合はreinterpret_cast、変換を行わずにデータを書き込む場合はostream::write()メソッドを使用しています。 Readingも同様の方法を使用します。一度に書き込まれる文字数を増やすことによって効率を改善することができます。

#include <fstream> 
#include <iostream> 
#include <boost/iostreams/filtering_stream.hpp> 
#include <boost/iostreams/filter/zlib.hpp> 
#include <cstdlib> 
#include <vector> 
#include <iomanip> 

int main() 
{ 
    using namespace std; 
    using namespace boost::iostreams; 

    const int NUM = 10000; 

    std::vector<float> data_out; 
    std::vector<float> data_in; 
    data_in.resize(NUM); 
    for(float i=0;i<NUM;i++) 
     data_out.push_back(233*(rand()/(float)RAND_MAX)); 

    { 
     ofstream file("/z/hello.z", ios_base::out | ios_base::binary); 
     filtering_ostream out; 
     out.push(zlib_compressor()); 
     out.push(file); 

     char *dptr = reinterpret_cast<char*>(data_out.data()); 

     for(int i=0;i<sizeof(float)*NUM;i++) 
     out.write(&dptr[i],1); 
    } 

    { 
     ifstream file_in("hello.z", ios_base::in | ios_base::binary); 
     filtering_istream in; 
     in.push(zlib_decompressor()); 
     in.push(file_in); 

     char *dptr = reinterpret_cast<char*>(data_in.data()); 

     for(int i=0;i<sizeof(float)*NUM;i++) 
     in.read(&dptr[i],1); 
    } 

    bool all_good=true; 
    for(int i=0;i<NUM;i++){ 
     cout<<std::setprecision(10)<<data_out[i]<<" "<<data_in[i]<<endl; 
     all_good &= (data_out[i]==data_in[i]); 
    } 

    cout<<"Good? "<<(int)all_good<<endl; 
} 
+0

ちょうど好奇心から、boost :: serializationを使用するとメモリ要件が倍増するとの結論に何を基づいていますか?私の理解から、それはあなたのように、基本的なストリームに書き込みます。何かがあれば、zlibをメモリフットプリントに使用することによる影響は、(内部データ構造全体で)はるかに重要になります。 –

+0

私はシリアル化に取り組んでからしばらくしていました。私がそうしたときに、シリアライズされた表現をメモリに保持する必要があり、それによって要件が倍増しました。私はおそらくストリーミング方法でシリアル化を使用する方法があると思います。私はBoostのシリアライズからCerealに移って依存関係を減らし、スピードを上げました([link](https://github.com/thekvs/cpp-serializers))。 – Richard

2

問題は圧縮ではなく、ベクトルの値をシリアル化する方法です。

圧縮を無効にして、簡単に検査のための10個の要素のサイズを制限する場合は、生成されたファイルは、このようなものに見えることがわかります。あなたが見ることができるように

0.001251260.5635850.1933040.808740.5850090.4798730.3502910.8959620.822840.746605 

、番号がテキストとして表現されているが小数点以下の桁数は限られており、区切り文字はありません。あなたのプログラムが遠隔的に賢明な結果を生むことができたのは、あなたが値< 1.0で作業しているからです。

数値型をテキストとしてフォーマットするstream operator <<を使用するためです。


最も簡単な解決策は、読み取りを処理するためにブースト::シリアル化を使用して書いているように見える(基礎となる圧縮ストリームとしてブースト::入出力ストリームを使用)です。私はバイナリアーカイブを使っていましたが、テキストアーカイブを使うこともできます(binary_をtext_に置き換えてください)。

サンプルコード:

#include <fstream> 
#include <iostream> 
#include <boost/iostreams/filtering_stream.hpp> 
#include <boost/iostreams/filter/zlib.hpp> 

#include <boost/archive/binary_oarchive.hpp> 
#include <boost/archive/binary_iarchive.hpp> 
#include <boost/serialization/vector.hpp> 

#include <cstdlib> 
#include <vector> 
#include <iomanip> 

int main() 
{ 
    using namespace std; 
    using namespace boost::iostreams; 

    const int NUM = 10; 

    std::vector<float> data_out; 
    for (float i = 0; i < NUM; i++) { 
     data_out.push_back(rand()/(float)RAND_MAX); 
    } 

    { 
     ofstream file("hello.z", ios_base::out | ios_base::binary); 
     filtering_ostream out; 
     out.push(zlib_compressor()); 
     out.push(file); 

     boost::archive::binary_oarchive oa(out); 
     oa & data_out; 
    } 

    std::vector<float> data_in; 
    { 
     ifstream file_in("hello.z", ios_base::in | ios_base::binary); 
     filtering_istream in; 
     in.push(zlib_decompressor()); 
     in.push(file_in); 

     boost::archive::binary_iarchive ia(in); 
     ia & data_in; 
    } 

    bool all_good=true; 
    for(int i=0;i<NUM;i++){ 
     cout<<std::setprecision(10)<<data_out[i]<<" "<<data_in[i]<<endl; 
     all_good &= (data_out[i]==data_in[i]); 
    } 

    cout<<"Good? "<<(int)all_good<<endl; 
} 

コンソール出力:

0.001251258887 0.001251258887 
0.563585341 0.563585341 
0.1933042407 0.1933042407 
0.8087404966 0.8087404966 
0.5850093365 0.5850093365 
0.4798730314 0.4798730314 
0.3502914608 0.3502914608 
0.8959624171 0.8959624171 
0.822840035 0.822840035 
0.7466048002 0.7466048002 
Good? 1 

マイナーな問題は、あなたがベクトルの大きさをシリアル化していないということですので、読むとき、あなたが読書を維持する必要がありますストリームの終わりまで

+0

ありがとう、ダン。あなたの適切な観察は、私が他のすべてを理解するのに十分であった。なぜ私が '' ''演算子が変換をしないことを期待しているのか分かりません。 – Richard

関連する問題