web-dev-qa-db-fra.com

Java FileInputStream ObjectInputStream atteint la fin du fichier EOF

J'essaie de lire le nombre de lignes dans un fichier binaire en utilisant readObject, mais j'obtiens IOException EOF. Est-ce que je le fais de la bonne façon?

    FileInputStream istream = new FileInputStream(fileName);
    ObjectInputStream ois = new ObjectInputStream(istream);

    /** calculate number of items **/
    int line_count = 0;
    while( (String)ois.readObject() != null){            
        line_count++;
    }
20
user69514

readObject() ne retourne pas null à EOF. Vous pouvez intercepter la variable EOFException et l'interpréter comme EOF, mais cela ne permettrait pas de détecter la distinction entre un EOF normal et un fichier tronqué. 

Une meilleure approche consisterait à utiliser certaines méta-données. Autrement dit, plutôt que de demander à la ObjectInput combien d'objets se trouvent dans le flux, vous devriez stocker le nombre quelque part. Par exemple, vous pouvez créer une classe de métadonnées qui enregistre le nombre et d’autres métadonnées et stocker une instance en tant que premier objet de chaque fichier. Vous pouvez également créer une classe de marqueur EOF spéciale et stocker une instance en tant que dernier objet de chaque fichier.

24
erickson

J'ai eu le même problème aujourd'hui. Bien que la question soit assez ancienne, le problème demeure et aucune solution propre n'a été fournie. Ignorer EOFException devrait être évité car il peut être levé lorsqu'un objet n'a pas été enregistré correctement. L'écriture de null vous empêche évidemment d'utiliser des valeurs nulles à d'autres fins. Enfin, l'utilisation de available() sur le flux d'objets renvoie toujours zéro, car le nombre d'objets est inconnu. 

Ma solution est assez simple. ObjectInputStream est juste un wrapper pour un autre flux, tel que FileInputStream. Bien que ObjectInputStream.available () renvoie zéro, FileInputStream.available retournera une valeur.

   FileInputStream istream = new FileInputStream(fileName);
   ObjectInputStream ois = new ObjectInputStream(istream);

   /** calculate number of items **/
   int line_count = 0;
   while( istream.available() > 0) // check if the file stream is at the end
   {
      (String)ois.readObject();    // read from the object stream,
                                   //    which wraps the file stream
      line_count++;
   }
19
Tomasz

Catch EOFException et utilisez-le pour terminer la boucle.

6
user207421

Si vous écrivez un objet null à la fin du fichier, lorsque vous le lirez, vous obtiendrez une valeur null et pourrez mettre fin à votre boucle.

Ajoutez simplement: Out.writeObject (null);

lorsque vous sérialisez les données.

1
C. Paul Bond

C'est curieux que l'API ne fournisse pas une solution plus élégante à cela. J'imagine que la variable EOFException fonctionnerait, mais j'ai toujours été encouragée à considérer les exceptions comme des événements inattendus, alors qu'ici, vous vous attendriez souvent à ce que le flux d'objets prenne fin.

J'ai essayé de contourner ce problème en écrivant une sorte d'objet "marqueur" pour signifier la fin du flux d'objet:

import Java.io.Serializable;

public enum ObjectStreamStatus implements Serializable {
    EOF
}


Puis, dans le code lisant l'objet, j'ai vérifié cet objet EOF dans la boucle de lecture d'objet.

1
Kevin Leahy

La méthode disponible de ObjectInputStream ne peut pas être utilisée pour terminer la boucle car elle renvoie 0 même s'il existe des objets à lire dans un fichier. L'écriture d'un null dans un fichier ne semble pas non plus être une bonne solution, car les objets peuvent être nuls, ce qui serait alors interprété comme la fin du fichier. Je pense que rattraper EOFException pour terminer les boucles est une meilleure pratique car si EOFException se produit (soit parce que vous avez atteint la fin du fichier, soit pour une autre raison), vous devez quand même terminer la boucle.

0
Eunwoo Song

Non, vous devez savoir combien d'objets il y a dans le fichier binaire. Vous pouvez écrire le nombre d'objets au début du fichier (en utilisant writeInt par exemple) et le lire pendant le chargement.

Une autre option consiste à appeler ois.available () et à boucler jusqu'à ce qu'il renvoie 0. Cependant, je ne suis pas sûr que cela soit sûr à 100%.

0
Manuel Darveau

Il semble que le problème réside dans les données que vous avez écrites. En supposant que les données soient écrites comme prévu par ce code, il ne devrait pas y avoir de problème.

(Je vois que vous lisez Strings. Cette ObectInputStream n'est pas destinée à la lecture de fichiers texte. Utilisez InputStreamReader et BufferedReader.readLine pour cela. De même, si vous avez écrit le fichier avec DataOutputSteam.writeUTF, lisez-le avec DataInputStream.readUTF)

0