[英]Read and write array to compressed file with boost iostreams
我想寫一個數組到一個文件,壓縮它,我去。
后來,我想從該文件中讀取數組,然后解壓縮它。
Boost的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;
}
而且,是的,我更喜歡以我的方式使用流操作符,而不是一次推送或拉動整個矢量塊。
問題不在於壓縮,而在於序列化向量值的方式。
如果禁用壓縮並將大小限制為10個元素以便於檢查,則可以看到生成的文件如下所示:
0.001251260.5635850.1933040.808740.5850090.4798730.3502910.8959620.822840.746605
如您所見,數字表示為文本,小數位數有限,沒有分隔符。 通過純粹的機會(因為你只使用值<1.0),你的程序能夠產生一個遠程合理的結果。
這是因為您使用流operator <<
將數字類型格式化為文本。
最簡單的解決方案似乎是使用boost :: serialization來處理讀寫(並使用boost :: iostreams作為底層壓縮流)。 我使用了二進制存檔,但你也可以使用文本存檔(只需用text_替換binary_)。
示例代碼:
#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
一個小問題是你沒有序列化向量的大小,所以在閱讀時你必須繼續閱讀直到流的結尾。
正如DanMašek在他們的回答中指出的那樣,我正在使用的<<
stream運算符是在壓縮之前將我的浮點數據轉換為文本表示。 出於某種原因,我沒有想到這一點。
使用序列化庫是避免這種情況的一種方法,但除了可能的開銷之外還會引入其他依賴項。
因此,我在浮點數據和ostream::write()
方法上使用了reinterpret_cast
來編寫數據,而無需一次轉換一個字符。 閱讀使用類似的方法。 通過增加一次寫入的字符數可以提高效率。
#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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.