web-dev-qa-db-ja.com

Java FileInputStream ObjectInputStreamがファイルの終わりに達したEOF

ReadObjectを使用してバイナリファイルの行数を読み取ろうとしていますが、IOException EOFが発生します。私はこれを正しい方法で行っていますか?

    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++;
    }
21
user69514

readObject()はEOFでnullを返しません。 EOFExceptionをキャッチしてEOFとして解釈することもできますが、これは通常のEOFが切り捨てられたファイルと区別できないため、検出に失敗します。

より良いアプローチは、いくつかのメタデータを使用することです。つまり、ObjectInputにストリーム内のオブジェクトの数を尋ねるのではなく、カウントをどこかに保存する必要があります。たとえば、カウントやその他のメタデータを記録するメタデータクラスを作成し、インスタンスを各ファイルの最初のオブジェクトとして保存できます。または、特別なEOFマーカークラスを作成し、インスタンスを各ファイルの最後のオブジェクトとして保存することもできます。

28
erickson

今日も同じ問題がありました。質問はかなり古いですが、問題は残っており、提供されたクリーンなソリューションはありませんでした。 EOFExceptionを無視すると、一部のオブジェクトが正しく保存されなかった場合にスローされる可能性があるため、無視する必要があります。 nullを書き込むと、他の目的でnull値を使用できなくなります。最後に、オブジェクトのストリームでavailable()を使用すると、オブジェクトの数が不明であるため、常にゼロが返されます。

私の解決策は非常に簡単です。 ObjectInputStreamは、FileInputStreamなどの他のストリームの単なるラッパーです。 ObjectInputStream.available ()はゼロを返しますが、FileInputStream.availableはいくつかの値を返します。

   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

いいえ。EOFExceptionをキャッチし、それを使用してループを終了します。

6
user207421

ファイルの最後にnullオブジェクトを書き込んだ場合、それを読み戻すとnull値が取得され、ループを終了できます。

追加するだけです:out.writeObject(null);

データをシリアル化するとき。

2
C. Paul Bond

APIがこれに対するよりエレガントなソリューションを提供しないのは不思議です。 EOFExceptionはうまくいくと思いますが、例外を予期しないイベントとして見るように常に促されてきましたが、ここでは、オブジェクトストリームが終了することを期待することがよくあります。

オブジェクトストリームの終わりを示す一種の「マーカー」オブジェクトを記述して、これを回避しようとしました:

import Java.io.Serializable;

public enum ObjectStreamStatus implements Serializable {
    EOF
}


次に、オブジェクトを読み取るコードで、これについてチェックしたEOFオブジェクト読み取りループのオブジェクト。

1
Kevin Leahy

ObjectInputStreamの利用可能なメソッドは、ファイルに読み込まれるオブジェクトがある場合でも0を返すため、ループを終了するために使用できません。ファイルにnullを書き込むことも、オブジェクトがnullになる可能性があるため、ファイルの終わりとして解釈されるため、良い解決策とは思えません。 EOFExceptionをキャッチしてループを終了することをお勧めします。これは、EOFExceptionが発生した場合(ファイルの終わりに到達したか、その他の理由により)、とにかくループを終了する必要があるためです。

0
Eunwoo Song

いいえ、バイナリファイルにあるオブジェクトの数を知る必要があります。ファイルの先頭にオブジェクトの数を書き込み(たとえば、writeIntを使用)、ロード中に読み取ることができます。

もう1つのオプションは、ois.available()を呼び出し、0を返すまでループすることです。ただし、これが100%確実かどうかはわかりません。

0
Manuel Darveau

問題はあなたが書いたデータにあるようです。データがこのコードで期待どおりに書き込まれていると仮定すると、問題は発生しません。

(私はあなたがStringsを読んでいるようです。これはObectInputStreamはテキストファイルを読み取るためのものではありません。そのためにInputStreamReaderおよびBufferedReader.readLineを使用してください。同様に、 DataOutputSteam.writeUTFでファイルし、DataInputStream.readUTFで読み取ります)