2010-03-19 18 views
11

¿Cómo puedo escribir 'un bit' en una secuencia de archivos o estructura de archivos cada vez? ¿Es posible escribir en una cola y luego lavarla? ¿es posible con C# o java? esto fue necesario cuando trato de implementar una instancia de codificación de Huffman. No puedo escribir bits en archivos. así que escríbalos en un conjunto de bits y luego (cuando se completó la compresión) escribe un fragmento de 8 bits cada vez (excluye el último).escribiendo 'bits' en secuencias de archivos C++

+0

¿Echas de menos algún idioma? La mayoría de los idiomas no permiten escribir menos de un byte a la vez. Sin embargo, puedes probar bits individuales e imprimir los resultados. – dirkgently

Respuesta

13

Buffering los bits individuales hasta que haya acumulado un byte entero parece una buena idea:

byte b; 
int s; 

void WriteBit(bool x) 
{ 
    b |= (x ? 1 : 0) << s; 
    s++; 

    if (s == 8) 
    { 
     WriteByte(b); 
     b = 0; 
     s = 0; 
    } 
} 

Usted apenas tiene que tratar con el caso en que el número de bits que se escriben no es un múltiplo de ocho.

+0

Se ve bien. El último caso podría manejarse con un argumento 'bool flush' y' if (s == 8 || flush) 'también. –

+0

Solo asegúrese de que s se inicialice en 0. –

+1

Tenga en cuenta también que ningún bit "primero" o "último" dentro de un byte está definido o implícito en el estándar C, simplemente más o menos significativo, tal vez "izquierdo" y "correcto" como se relaciona con los cambios. Así que WriteBit tendrá que decidir por sí mismo (y documentar) si los bits deberían escribirse primero o menos significativos primero. Has ido por lo menos significativo, lo cual es bastante justo y Wikipedia afirma que es de lejos el más común en el nivel de hardware para las comunicaciones en serie. Nunca lo había hecho lo suficientemente profundo en un controlador de serie para saberlo por mí mismo. –

3

¿Qué sistema de archivos está utilizando?

Lo más probable es que almacene la longitud del archivo en bytes (¿hay que no?), Por lo que es imposible tener un archivo físico que no contenga un número entero de bytes.

Así que si está escribiendo en el archivo como una secuencia de bits, o bien tiene que truncar los últimos bits cuando haya terminado, o escribir el último byte con lo que significa juntar en los bits restantes.

He aquí algunos Python código para que pueda empezar

class BitFile(file): 
    def __init__(self, filename, mode): 
     super(BitFile, self).__init__(filename, mode) 
     self.bitCount=0 
     self.byte = 0 

    def write(self, bit): 
     self.bitCount+=1 
     self.byte = self.byte*2+bit 
     if self.bitCount%8==0: 
      super(BitFile, self).write(chr(self.byte)) 
      self.byte=0 

    def close(self): 
     if self.bitCount%8!=0: 
      super(BitFile, self).write(chr(self.byte)) 
     super(BitFile, self).close()  

with BitFile("bitfile.bin","w") as bf: 
    bf.write(1) 
    bf.write(1) 
    bf.write(1) 
    bf.write(0) 
    bf.write(0) 
    bf.write(0) 
    bf.write(0) 
    bf.write(0) 
    bf.write(1) 
0

Realmente no se puede. Estoy bastante seguro de que el problema no está en el lenguaje o el sistema de archivos, sino en un problema de hardware. Los procesadores están diseñados para trabajar con bytes. Probablemente lo más cercano que puede hacer es escribir su último byte una y otra vez, con acolchado con ceros, cambiándolos sobre la marcha, uno a la vez.

manera de escribir bits '11011', que podrían hacer lo siguiente (ejemplo pitón, pero cualquier lenguaje debe tener instalaciones para hacer esto:

f.write(chr(0b10000000)) 
f.flush() 
f.seek(-1) 
f.write(chr(0b11000000)) 
f.flush() 
f.seek(-1) 
f.write(chr(0b11000000)) 
f.flush() 
f.seek(-1) 
f.write(chr(0b11010000)) 
f.flush() 
f.seek(-1) 
f.write(chr(0b11011000)) 
f.flush() 

No estaba esperando para obtener algún tipo de ganancia de rendimiento de esta estabas?

+0

Para su información, los idiomas C y C++ no tienen facilidades para declarar constantes binarias. –

0

recomendaría asignar un búfer bastante grande (4096 bytes por lo menos) y enjuague que fuera en el disco cada vez que se llena. el uso de un tampón de un byte suele causar un mal desempeño.

+0

si quiero comprimir un archivo enorme, como un glifo pos datos de otf arabic. su tamaño es de 48 MB, después de copmressing es de 29 MB. entonces tu método no es teórico y desperdicia memoria. –

+1

Has entendido mal mi método. Simplemente estoy sugiriendo un búfer más grande que un byte, para hacer que el enjuague sea mucho menos frecuente, no un búfer para que quepan todos sus datos. – Tronic

0

I Hizo esto una vez para la decodificación huffman y terminó escribiendo los bits como caracteres y manejando todo internamente como una simple cadena en C.

De esta manera, no tiene que preocuparse por el byte final y también es legible por el ser humano. También es más fácil verificar bits, ya que solo es cuestión de direccionar la matriz de caracteres (binbuf[123] == '1') en lugar de tener que manipular bits. No es la solución más optimizada, pero resolvió mi problema cuidadosamente.

El inconveniente obvio es que esta representación usa más memoria.

8

Puede utilizar boost::dynamic_bitset junto con std::ostream_iterator para lograr el resultado deseado de una manera concisa:

#include <fstream> 
#include <iterator> 
#include <boost/dynamic_bitset.hpp> 

typedef boost::dynamic_bitset<unsigned char> Bitset; 

// To help populate the bitset with literals */ 
Bitset& operator<<(Bitset& lhs, bool val) {lhs.push_back(val); return lhs;} 

int main() 
{ 
    Bitset bitset; 
    bitset<<0<<1<<0<<1<<0<<1<<0<<1 
      <<1<<0<<1<<0; 

    std::ofstream os("data.dat", std::ios::binary); 
    std::ostream_iterator<char> osit(os); 
    boost::to_block_range(bitset, osit); 

    return 0; 
} 

I hizo que el tamaño de bloque de mis dynamic_bitset 8 bits especificando unsigned char como el parámetro de plantilla.Puede aumentar el tamaño del bloque al especificar un tipo de entero más grande.

boost::to_block_range vuelca el conjunto de bits en bloques al repetidor de salida dado. Si hay bits de resto vacíos en el último bloque, se rellenarán con cero.

Cuando abro data.dat en un editor hexadecimal, veo: AA 05. Esto está en una pequeña plataforma endian (x64).

0

El problema aquí es que muchas plataformas no tienen acceso directo a los bits. Agrupan bits en un paquete mínimo, muchas veces el byte o palabra. Además, el protocolo para dispositivos de flujo no facilita la transmisión de bits individuales.

El método común para tratar con bits individuales es empacarlos en la unidad portátil más pequeña y accesible (direccionable). Los bits no utilizados generalmente se establecen en cero. Esto se puede lograr con operaciones aritméticas binarias (OR, AND, EXCLUSIVE-OR, NOT, etc.).

Con los procesadores modernos, los movimientos de los bits ralentizan la máquina y el rendimiento. La memoria es barata y con espacios de direccionamiento grandes, la justificación para el empaquetado de bits se ha vuelto más difícil. Generalmente, el empaquetado de bits está reservado para operaciones orientadas a hardware (y también protocolos de transmisión). Por ejemplo, si la capacidad de de un procesador es de 16 bits, el procesador probablemente pueda manejar 16 palabras más rápido que las manipulaciones de 16 bits en una palabra.

Además, tenga en cuenta que escribir desde y hacia la memoria suele ser más rápido que la E/S de las transmisiones. Los sistemas eficientes almacenan los datos en la memoria antes de transmitir los datos. Es posible que desee considerar esta técnica en sus diseños. La reducción de las operaciones de E/S mejorará el rendimiento de su programa.