C++ 使用boost iostreams将阵列读写到压缩文件
我想将一个数组写入一个文件,在运行时对其进行压缩 稍后,我想从该文件中读取数组,并在运行时对其进行解压缩 Boost的Iostreams似乎是一个很好的方法,因此我构建了以下代码。不幸的是,输出和输入数据在最后并不相等。但他们几乎做到了:C++ 使用boost iostreams将阵列读写到压缩文件,c++,boost,compression,boost-iostreams,C++,Boost,Compression,Boost Iostreams,我想将一个数组写入一个文件,在运行时对其进行压缩 稍后,我想从该文件中读取数组,并在运行时对其进行解压缩 Boost的Iostreams似乎是一个很好的方法,因此我构建了以下代码。不幸的是,输出和输入数据在最后并不相等。但他们几乎做到了: Output Input 0.8401877284 0.8401880264 0.3943829238 0.3943830132 0.7830992341 0.7830989957 0.7984400392 0.79843997
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;
}
//使用:g++test.cpp--std=c++11-lz-lboost\u iostreams编译
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main()
{
使用名称空间std;
使用名称空间boost::iostreams;
常数int NUM=10000;
std::矢量数据输出;
std::矢量数据输入;
调整数据大小(NUM);
对于(float i=0;i而言,问题不在于压缩,而在于序列化向量值的方式
如果禁用压缩并将大小限制为10个元素以便于检查,则可以看到生成的文件如下所示:
0.001251260.5635850.1933040.808740.5850090.4798730.3502910.8959620.822840.746605
正如您所看到的,数字以文本形式表示,小数位数有限,并且没有分隔符。您的程序能够产生一个远程可感知的结果完全是偶然的(因为您只处理<1.0的值)
这是因为您使用了将数字类型格式化为文本的
最简单的解决方案似乎是使用boost::serialization来处理读写操作(并使用boost::iostreams作为底层压缩流)。我使用了二进制存档,但您也可以简单地使用文本存档(只需将二进制文件替换为文本文件)
示例代码:
#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;
}
一个小问题是,您没有序列化向量的大小,因此在读取时,您必须一直读取到流的末尾。正如Dan Mašek在中指出的那样,当您将压缩排除在样本之外时,是否也会出现问题?是的,它会出现,只是尝试了一下。您正在将浮点数作为字符串打印到文件中。A没有分隔符的lso。只有通过保存小于1的值,您才能获得远程感知的内容,因为否则它将是不可解析的。我不认为不需要分隔符来进行压缩/解压缩:我猜想(可能是错误的)当有足够的数据可用时,浮点数被推入内部字节缓冲区并进行压缩。解压的工作原理类似:数据被读取到内部缓冲区,并在有足够的信息可用时从内部缓冲区中取出。换句话说,无压缩的打印会使边界的位置模糊不清因为4字节浮点由输出中的可变字节数表示。压缩时不会出现歧义,因为读/写操作一直持续到翻译了4个字节的数据。如果您将其存储为文本,则会出现歧义,除非这不是您想要的,或者您希望使用一致的数字将其打印为文本字符数(但是您可能需要与默认的运算符>>
不同的内容来读取它)谢谢你,丹。你敏锐的观察足以让我弄明白其他的一切。我不知道为什么我只是出于好奇而期待,你是基于什么得出使用boost::serialization会使内存需求翻倍的结论的?据我所知,它会像你一样写入底层流。如果有的话ng,使用zlib对内存占用的影响将更加显著(对于其所有内部数据结构).我的错,我已经有一段时间没有使用序列化了。当我这样做时,序列化表示需要保存在内存中,这使要求增加了一倍。我想可能有一种方法可以以流式方式使用序列化。我不再使用Boost序列化,而是使用grane来减少依赖性和提高速度()。
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
#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;
}