2011-01-12 6 views
5

How to write bitset data to a file?¿Cómo se almacena un vector <bool> o un conjunto de bits en un archivo, pero en bits?

La primera respuesta no responde la pregunta correctamente, ya que requiere 8 veces más espacio del que debería.

¿Cómo lo harías? Realmente lo necesito para guardar una gran cantidad de valores verdadero/falso.

+0

En realidad, no me importaba que guardara cada bit como un byte en mi pregunta ... estaba redactado de forma ambigua. Buena pregunta de seguimiento. –

Respuesta

5

Enfoque más simple: tome 8 valores booleanos consecutivos, representélos como un solo byte, escriba ese byte en su archivo. Eso ahorraría mucho espacio.

Al principio del archivo, puede escribir el número de booleanos valores que desea escribir en el archivo; ese número ayudará mientras lee los bytes del archivo y los convierte nuevamente en valores booleanos.

-1

dos opciones:

pasar las libras adicionales (o, más probablemente peniques) para un disco más grande.

Escriba una rutina para extraer 8 bits del conjunto de bits a la vez, compórtelos en bytes y escríbalos en la secuencia de salida.

+0

así que quiero almacenar un s tanto como sea posible, por lo que la capacidad aumentada por un factor de 8 es mejor que comprar comprar comprar. – jokoon

+1

No fue muy útil en absoluto ... –

1

Una forma podría ser:

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

Tenga en cuenta que esto supone no le importa lo que termina el diseño poco siendo en la memoria, porque hace ningún ajuste para cualquier cosa. Pero siempre y cuando también serialice la cantidad de bits que se almacenaron realmente (para cubrir casos en los que tiene un conteo de bits que no es un múltiplo de CHAR_BITS) puede deserializar exactamente el mismo conjunto de bits o vector que tenía originalmente como este .

(No estoy contento con el cálculo del tamaño de la cubeta, pero es 1 a.m. y tengo problemas para pensar en algo más elegante).

1

Aquí hay una prueba con dos funciones que usarán un número mínimo de bytes, sin comprimir el conjunto de bits.

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

Tenga en cuenta que probablemente usando un reinterpret_cast de la porción de memoria utilizada por el bitset como una matriz de caracteres también podrían funcionar, pero es tal vez cruzando los sistemas no portátiles, ya que no sabe lo que la representación de la bitset es (endianness?)

2

Si desea la clase de bitset que mejor admite la conversión a binario, y su conjunto de bits es más que el tamaño de unsigned long, entonces la mejor opción es boost::dynamic_bitset. (Supongo que son más de 32 e incluso 64 bits si le preocupa ahorrar espacio).

Desde dynamic_bitset puede usar to_block_range para escribir los bits en el tipo integral subyacente. Puede construir el dynamic_bitset desde los bloques utilizando from_block_range o su constructor desde BlockInputIterator o realizando llamadas a append().

Ahora que tiene los bytes en su formato nativo (Bloque), todavía tiene el problema de escribirlo en una secuencia y leerlo de nuevo.

Primero tendrá que almacenar un poco de información de "encabezado": la cantidad de bloques que tiene y posiblemente la endianidad.O puede usar una macro para convertir a una endianidad estándar (por ejemplo, ntohl pero idealmente usará una macro que no es operativa para su plataforma más común, por lo que si es poco endiablada probablemente quiera almacenar de esa manera y convertir solo para sistemas big-endian).

(Nota: asumo que boost :: dynamic_bitset convierte de forma estándar los tipos integrales de la misma manera, independientemente de la endiancia subyacente. Su documentación no lo dice).

Para escribir números binarios en una secuencia use os.write(&data[0], sizeof(Block) * nBlocks) y para leer el uso. read(&data[0], sizeof(Block) * nBlocks) donde se supone que los datos son vector<Block> y antes de leer debe hacer data.resize(nBlocks) (no reserve()). (También puede hacer cosas raras con istream_iterator o istreambuf_iterator pero resize() es probablemente mejor).

+1

Hice un código con un vector >, lo probaré más tarde – 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); 
Cuestiones relacionadas