2010-03-19 2 views
11

Comment puis-je écrire «un bit» dans un flux de fichier ou une structure de fichier à chaque fois? est-il possible d'écrire dans une file d'attente puis de la vider? est-ce possible avec C# ou java? cela était nécessaire lorsque j'ai essayé d'implémenter une instance de codage Huffman. Je ne peux pas écrire des bits dans des fichiers. écrivez-les donc sur un bitset puis (une fois la compression terminée) écrivez-en 8 bits à chaque fois (en excluant la dernière).écrire des «bits» dans les flux de fichiers C++

+0

Avez-vous manqué une langue? La plupart des langues ne permettent pas d'écrire moins d'un octet à la fois. Vous pouvez tester des bits individuels et imprimer les résultats. – dirkgently

Répondre

13

les Buffering bits individuels jusqu'à ce que vous avez accumulé un octet tout semble être une bonne idée:

byte b; 
int s; 

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

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

Il vous suffit de traiter le cas où le nombre de bits à écrire est pas un multiple de huit.

+0

Ça a l'air bien. Le dernier cas pourrait être manipulé avec un argument 'bool flush' et' if (s == 8 || flush) 'aussi. –

+0

Assurez-vous simplement que s est initialisé à 0. –

+1

Notez également qu'aucun bit "premier" ou "dernier" dans un octet n'est défini ou implicite dans la norme C, juste le plus ou le moins significatif, peut-être "gauche" et "droite" cela concerne les changements. Donc, WriteBit devra décider pour lui-même (et le document) si les bits doivent être écrits les plus ou les moins significatifs en premier. Vous êtes allé pour le moins significatif, ce qui est assez juste et Wikipedia prétend que c'est de loin le plus commun au niveau du matériel pour les communications série. Je ne l'ai jamais fait assez profond dans un pilote de série pour savoir pour moi-même. –

3

Quel système de fichiers utilisez-vous? Il est probable qu'il stocke la longueur du fichier en octets (y a-t-il qui ne le fait pas?), Il est donc impossible d'avoir un fichier physique qui ne soit pas un nombre entier d'octets. Par conséquent, si vous écrivez dans le fichier sous la forme d'un flux de bits, vous devez soit tronquer les derniers bits lorsque vous avez terminé, soit écrire l'octet final avec ce qui est ammount to junk dans les bits restants.

Voici quelques code Python pour vous lancer

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

Vous ne pouvez pas vraiment. Je suis assez sûr que le problème n'est pas avec la langue ou le système de fichiers, mais un problème matériel. Les processeurs sont conçus pour fonctionner avec des octets. Probablement le plus proche que vous pouvez faire est d'écrire votre dernier octet encore et encore, droite rembourré avec des zéros, en les changeant comme vous allez, un à la fois.

ainsi écrire des bits « 11011 », vous pouvez faire ce qui suit (exemple de python, mais ne importe quelle langue devrait avoir des installations pour le faire:

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() 

Vous ne avez pas l'espoir d'obtenir une sorte de gain de performance de ce étiez-vous?

+0

FYI, les langages C et C++ n'ont pas de possibilités pour déclarer des constantes binaires. –

0

Je recommande l'attribution d'un tampon assez grand (4096 octets au moins) et rincez que hors le disque chaque fois qu'il remplit. L'utilisation d'un tampon d'un octet provoque généralement une mauvaise performance.

+0

si je veux compresser un fichier énorme, comme un glyphe pos données d'otf arabe. sa taille est de 48 Mo, après copmressing est de 29 Mo. Donc, votre méthode n'est pas théorique. et gaspille de la mémoire. –

+1

Vous avez mal compris ma méthode. Je suggère simplement un tampon plus grand qu'un octet, pour que la vidange soit beaucoup moins fréquente, et non pas un tampon pour l'ensemble de vos données. – Tronic

0

I l'a fait une fois pour décodage Huffman et fini écrire les bits comme caractères et ainsi gérer tout en interne comme une simple chaîne de caractères en C. De cette façon, vous n'avez pas à vous inquiéter de l'octet de queue et il est également lisible par l'utilisateur. Il est également plus facile de vérifier les bits car il suffit d'adresser le tableau char (binbuf[123] == '1') au lieu de manipuler des bits. Pas la solution la plus optimisée, mais elle a résolu mon problème soigneusement.

L'inconvénient évident est que cette représentation utilise plus de mémoire.

8

Vous pouvez utiliser boost::dynamic_bitset avec std::ostream_iterator pour obtenir le résultat souhaité d'une manière concise:

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

J'ai fait la taille du bloc de mes dynamic_bitset 8 bits en spécifiant unsigned char comme paramètre de modèle.Vous pouvez agrandir la taille du bloc en spécifiant un type entier plus grand.

boost::to_block_range vide l'ensemble de bits en blocs vers l'itérateur de sortie donné. S'il y a des bits restants vides dans le dernier bloc, ils seront complétés avec zéro.

Lorsque j'ouvre data.dat dans un éditeur hexadécimal, je vois: AA 05. C'est sur une petite plate-forme d'Endian (x64).

0

Le problème ici est que de nombreuses plates-formes n'ont pas d'accès direct aux bits. Ils regroupent les bits dans un paquet minimal, souvent le octet ou le mot. En outre, le protocole pour les dispositifs de flux ne facilite pas la transmission de bits individuels.

La méthode courante pour traiter des bits individuels consiste à les empaqueter dans la plus petite unité portable et accessible (adressable). Les bits inutilisés sont généralement mis à zéro. Cela peut être accompli avec des opérations arithmétiques binaires (OR, AND, EXCLUSIVE-OR, NOT, etc.).

Avec les processeurs modernes, le trépan ralentit la machine et la performance. La mémoire est bon marché et avec de grands espaces d'adressage, la justification de l'empaquetage est devenue plus difficile. Généralement, l'empaquetage est réservé aux opérations orientées matériel (et aussi aux protocoles de transmission). Par exemple, si la capacité du mot d'un processeur est de 16 bits, le processeur peut probablement gérer 16 mots plus rapidement que les manipulations 16 bits en un seul mot. De plus, gardez à l'esprit que l'écriture vers et depuis la mémoire est souvent plus rapide que les E/S des flux. Les systèmes efficaces tamponnent les données en mémoire avant de transmettre les données. Vous pouvez vouloir considérer cette technique dans vos conceptions. La réduction des opérations d'E/S améliorera les performances de votre programme.

Questions connexes