2009-09-04 8 views
6

J'ai un BitSet et je veux l'écrire dans un fichier - Je suis tombé sur une solution pour utiliser un ObjectOutputStream en utilisant la méthode writeObject.écrire un BitSet dans un fichier en Java

Je regardais les ObjectOutputStream dans l'API java et vu que vous pouvez écrire d'autres choses (octet, int, court etc)

j'ai essayé de vérifier la classe alors j'ai essayé d'écrire un octet dans un fichier en utilisant le code suivant mais le résultat me donne un fichier avec 7 octets au lieu de 1 octet

ma question est quels sont les 6 premiers octets dans le fichier? pourquoi sont-ils là? Ma question est pertinente pour un BitSet parce que je ne veux pas commencer à écrire beaucoup de données dans un fichier et réaliser que j'ai des octets aléatoires insérés dans le fichier sans savoir ce qu'ils sont.

est ici le code:

byte[] bt = new byte[]{'A'}; 
    File outFile = new File("testOut.txt"); 
    FileOutputStream fos = new FileOutputStream(outFile); 
    ObjectOutputStream oos = new ObjectOutputStream(fos); 
    oos.write(bt); 
    oos.close(); 

Merci pour toute aide

Avner

Répondre

2

Les autres octets seront des informations de type.

Fondamentalement, ObjectOutputStream est une classe utilisée pour écrire des objets Serializable vers une destination (généralement un fichier). Cela a plus de sens si vous pensez à InputObjectStream. Il a une méthode readObject() dessus. Comment Java sait-il quel objet instancier? Facile: il y a des informations de type là-dedans.

+0

donc si je vous comprends bien - chaque fois que j'écris quelque chose en utilisant ObjectOutputStream je reçois des frais généraux sérieux pour chaque écriture. par exemple si j'écris un int, un court, un octet et puis une chaîne Je reçois 4 ensembles de données supplémentaires pour chaque article que j'écris? – Avner

+2

Non. Seule la méthode writeObject() ajoute l'en-tête de type. La méthode writeUTF() ajoute un préfixe de longueur de 2 octets. Les méthodes writeXX() primitives n'ajoutent pas de surcharge. Lisez le document API pour plus de détails. –

+1

Notez également que les informations de type sont par objet. Pour un objet qui consiste essentiellement en un tableau primitif (tel que BitSet), le surcoût est constant, quelle que soit la taille du tableau. –

1

Vous pourriez écrire des objets vers un ObjectOutputStream, de sorte que le flux contient des informations sur les types écrits comme ainsi que les données nécessaires pour reconstituer l'objet.

Si vous savez que le flux sera toujours contenir un BitSet, ne pas utiliser un ObjectOutputStream - et si l'espace est une prime, puis convertir le BitSet à un ensemble d'octets où chaque bit correspond à un bit dans le BitSet, puis écrivez cela directement dans le flux sous-jacent (par exemple un FileOutputStream comme dans votre exemple).

+0

Malheureusement, BitSet n'a pas de méthode intégrée pour le convertir en un tableau d'octets. – finnw

+0

Il existe la méthode: 'toByteArray()' – clankill3r

+0

@ clankill3r: Oui, avec 'toLongArray()', mais seulement depuis Java 7. – charlie

0

Le format de sérialisation, comme beaucoup d'autres, inclut un en-tête avec le nombre magique et l'information de version. Lorsque vous utilisez DataOutput/OutputStream méthodes sur ObjectOutputStream sont placés au milieu des données sérialisées (sans informations de type). Cela est généralement effectué uniquement dans writeObject implémentations après un appel à defaultWriteObject ou l'utilisation de putFields.

0

Si vous n'utilisez que le BitSet enregistré dans Java, la sérialisation fonctionne correctement. Cependant, c'est un peu ennuyeux si vous voulez partager le bitset sur plusieurs plates-formes. Outre la surcharge de la sérialisation Java, le BitSet est stocké en unités de 8 octets. Cela peut générer trop de frais si votre bitset est petit.

Nous avons écrit cette petite classe afin que nous puissions exclure les tableaux d'octets de BitSet. En fonction de votre utilisation, cela peut fonctionner mieux que la sérialisation Java pour vous.

public class ExportableBitSet extends BitSet { 

    private static final long serialVersionUID = 1L; 

    public ExportableBitSet() { 
     super(); 
    } 

    public ExportableBitSet(int nbits) { 
     super(nbits); 
    } 

    public ExportableBitSet(byte[] bytes) { 
     this(bytes == null? 0 : bytes.length*8);   
     for (int i = 0; i < size(); i++) { 
      if (isBitOn(i, bytes)) 
       set(i); 
     } 
    } 

    public byte[] toByteArray() { 

     if (size() == 0) 
      return new byte[0]; 

     // Find highest bit 
     int hiBit = -1; 
     for (int i = 0; i < size(); i++) { 
      if (get(i)) 
       hiBit = i; 
     } 

     int n = (hiBit + 8)/8; 
     byte[] bytes = new byte[n]; 
     if (n == 0) 
      return bytes; 

     Arrays.fill(bytes, (byte)0); 
     for (int i=0; i<n*8; i++) { 
      if (get(i)) 
       setBit(i, bytes); 
     } 

     return bytes; 
    } 

    protected static int BIT_MASK[] = 
     {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; 

    protected static boolean isBitOn(int bit, byte[] bytes) { 
     int size = bytes == null ? 0 : bytes.length*8; 

     if (bit >= size) 
      return false; 

     return (bytes[bit/8] & BIT_MASK[bit%8]) != 0; 
    } 

    protected static void setBit(int bit, byte[] bytes) { 
     int size = bytes == null ? 0 : bytes.length*8; 

     if (bit >= size) 
      throw new ArrayIndexOutOfBoundsException("Byte array too small"); 

     bytes[bit/8] |= BIT_MASK[bit%8]; 
    } 
} 
Questions connexes