Vector またはビットセットをファイルにどのように保存しますか?
質問
最初の答えでは、質問に正しく答えません。なぜなら、必要以上に8倍のスペースが必要だからです。
どうしますか?私は本当に多くの真/偽の値を保存するためにそれが必要です。
解決
最も単純なアプローチ:連続した8ブール値を取り、それらを単一のバイトとして表し、そのバイトをファイルに書き込みます。それは多くのスペースを節約します。
ファイルの先頭では、の数を書くことができます ブール ファイルに書き込みたい値。その数は、ファイルからバイトを読み取り、それらをブール値に戻すときに役立ちます!
他のヒント
バイナリへの変換を最適にサポートするビットセットクラスが必要な場合、ビットセットが符号なしのサイズよりも大きい場合、使用する最良のオプションは boost :: dynamic_bitset. 。 (あなたがスペースを節約することを心配しているなら、それは32以上、さらには64ビットであると思います)。
dynamic_bitesetからto_block_rangeを使用して、基礎となる積分型にビットを書き込むことができます。 from_block_rangeまたはblockinputiteratorのコンストラクターを使用するか、append()呼び出しを行うことにより、ブロックから動的_bitesetを構築できます。
これで、ネイティブ形式(ブロック)のバイトが作成されました。ストリームに書き留めて読み戻すという問題があります。
最初に「ヘッダー」情報を少し保存する必要があります。これは、持っているブロックの数と、潜在的にはエンディアンです。または、マクロを使用して標準的なエンディアンネスに変換される場合があります(例:ntohlですが、最も一般的なプラットフォームにはオプでないマクロを使用することができます。ビッグエンディアンシステム)。
(注:boost :: dynamic_bitsetは、根底にあるendiannessに関係なく同じ方法で積分タイプを標準的に変換すると想定しています。彼らの文書は言っていません)。
バイナリをストリーム使用に記述するには os.write( &data[0], sizeof(Block) * nBlocks )
そして、使用を読むのはです。read( &data[0], sizeof(Block) * nBlocks )
データが想定される場所 vector<Block>
そして、読む前にあなたはしなければなりません data.resize(nBlocks)
(いいえ reserve()
)。 (奇妙なことをすることもできます istream_iterator
また istreambuf_iterator
しかし、semeize()はおそらくより良いです)。
ビットセットを圧縮せずに最小限の数のバイトを使用する2つの関数を使用して試してみます。
template<int I>
void bitset_dump(const std::bitset<I> &in, std::ostream &out)
{
// export a bitset consisting of I bits to an output stream.
// Eight bits are stored to a single stream byte.
unsigned int i = 0; // the current bit index
unsigned char c = 0; // the current byte
short bits = 0; // to process next byte
while(i < in.size())
{
c = c << 1; //
if(in.at(i)) ++c; // adding 1 if bit is true
++bits;
if(bits == 8)
{
out.put((char)c);
c = 0;
bits = 0;
}
++i;
}
// dump remaining
if(bits != 0) {
// pad the byte so that first bits are in the most significant positions.
while(bits != 8)
{
c = c << 1;
++bits;
}
out.put((char)c);
}
return;
}
template<int I>
void bitset_restore(std::istream &in, std::bitset<I> &out)
{
// read bytes from the input stream to a bitset of size I.
/* for debug */ //for(int n = 0; n < I; ++n) out.at(n) = false;
unsigned int i = 0; // current bit index
unsigned char mask = 0x80; // current byte mask
unsigned char c = 0; // current byte in stream
while(in.good() && (i < I))
{
if((i%8) == 0) // retrieve next character
{ c = in.get();
mask = 0x80;
}
else mask = mask >> 1; // shift mask
out.at(i) = (c & mask);
++i;
}
}
おそらく、ビットセットで使用されているメモリの部分の再解釈を使用すると、チャーの配列としても機能する可能性があることに注意してください。
1つの方法は次のとおりです。
std::vector<bool> data = /* obtain bits somehow */
// Reserve an appropriate number of byte-sized buckets.
std::vector<char> bytes((int)std::ceil((float)data.size() / CHAR_BITS));
for(int byteIndex = 0; byteIndex < bytes.size(); ++byteIndex) {
for(int bitIndex = 0; bitIndex < CHAR_BITS; ++bitIndex) {
int bit = data[byteIndex * CHAR_BITS + bitIndex];
bytes[byteIndex] |= bit << bitIndex;
}
}
これは、ビットレイアウトがメモリになっていることを気にしないと仮定していることに注意してください。しかし、実際に保存されたビットの数をシリアル化する限り(char_bitsの倍数ではないいくつかのカウントがあるケースをカバーするため) 。
(私はそのバケットサイズの計算に満足していませんが、午前1時で、もっとエレガントなものを考えるのに苦労しています)。
#include "stdio"
#include "bitset"
...
FILE* pFile;
pFile = fopen("output.dat", "wb");
...
const unsigned int size = 1024;
bitset<size> bitbuffer;
...
fwrite (&bitbuffer, 1, size/8, pFile);
fclose(pFile);
2つのオプション:
より大きなディスクのために、余分なポンド(またはペンス、より可能性が高い)を費やします。
一度にビットセットから8ビットを抽出するルーチンを作成し、それらをバイトに作成し、出力ストリームに書き込みます。