2011-01-12 5 views

risposta

5

Approccio più semplice: prendere 8 valori booleani consecutivi, rappresentarli come un singolo byte, scrivere quel byte nel file. Ciò farebbe risparmiare molto spazio.

All'inizio del file, è possibile scrivere il numero di valori booleani che si desidera scrivere nel file; quel numero aiuterà durante la lettura dei byte dal file e li riconvertirà in valori booleani!

-1

due opzioni:

spendere i chili in più (o pence, più probabile) per un disco più grande.

Scrivere una routine per estrarre 8 bit dal bitset alla volta, comporli in byte e scriverli nel flusso di output.

+0

beh voglio archiviare il più possibile, quindi aumentare la capacità di un fattore 8 è meglio che comprare comprare comprare. – jokoon

+1

Non molto utile a tutti ... –

1

Un modo potrebbe essere:

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; 
    } 
} 

Si noti che questo presuppone che non si cura ciò che il layout po 'finisce per essere in memoria, perché rende regolazioni per qualsiasi cosa. Ma fino a quando serializzi anche il numero di bit che sono stati effettivamente archiviati (per coprire casi in cui hai un numero di bit che non è un multiplo di CHAR_BITS) puoi deserializzare esattamente lo stesso set di bit o vettore come all'inizio .

(Non sono contento del calcolo della dimensione del secchio ma è l'una e ho difficoltà a pensare a qualcosa di più elegante).

1

Ecco una prova con due funzioni che utilizzeranno un numero minimo di byte, senza comprimere il set di bit.

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; 
    } 
} 

Nota che probabilmente usando una reinterpret_cast della porzione di memoria utilizzata dal bitset come un array di caratteri potrebbe anche funzionare, ma è forse sistemi attraversavano non portatili, perché non si sa che cosa la rappresentazione della bitset is (endianness?)

2

Se si desidera che la classe di bitset che meglio supporta la conversione in binario e il proprio set di bit superi le dimensioni di unsigned long, la migliore opzione da utilizzare è boost::dynamic_bitset. (Presumo che sia più di 32 e anche 64 bit se sei preoccupato di risparmiare spazio).

Da dynamic_bitset è possibile utilizzare to_block_range per scrivere i bit nel tipo integrale sottostante. Puoi ricostruire il dynamic_bitset dai blocchi usando from_block_range o il suo costruttore da BlockInputIterator o effettuando le chiamate append().

Ora i byte sono nel loro formato nativo (Blocco), si ha ancora il problema di scriverlo in un flusso e di leggerlo di nuovo.

È necessario memorizzare prima un po 'di informazioni di "intestazione": il numero di blocchi che si hanno e potenzialmente l'endianness.Oppure potresti usare una macro per convertire in un endianness standard (es. Ntohl ma useresti idealmente una macro che è no-op per la tua piattaforma più comune quindi se questo è little-endian probabilmente vorrai memorizzare in quel modo e convertire solo per sistemi big-endian).

(Nota: suppongo che boost :: dynamic_bitset converta in modo standard i tipi di integrale nello stesso modo indipendentemente dall'endianità sottostante, la loro documentazione non dice).

Per scrivere numeri binari su un flusso utilizzare os.write(&data[0], sizeof(Block) * nBlocks) e leggere l'uso è. read(&data[0], sizeof(Block) * nBlocks) dove si presume che i dati siano vector<Block> e prima di leggere è necessario eseguire data.resize(nBlocks) (non reserve()). (Puoi anche fare cose strane con istream_iterator o istreambuf_iterator ma ridimensionare() è probabilmente meglio).

+1

Ho fatto un po 'di codice con un vettore >, lo proverò più tardi – jokoon

0
#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);