4

RandomAccessFilesを使用するJavaのFileChannelクラスを使用してファイルを作成しました。ファイル内のさまざまな場所にオブジェクトを書き込みました。オブジェクトのサイズは可変でしたが、すべて同じクラスでした。私は次のアイデアを使用してオブジェクトを作成しました:

ByteArrayOutputStream bos= new ByteArrayOutputStream();
        ObjectOutput out = new ObjectOutputStream(bos);
        out.writeObject(r);
        byte[] recordBytes= bos.toByteArray();

    ByteBuffer rbb= ByteBuffer.wrap(recordBytes);

    while(rbb.hasRemaining()) {
        fileChannel.write(rbb);
    }

今、私はそのようなファイルから読みたいです。読み取るバイト数を指定する必要はありません。オブジェクト入力ストリームを使用してオブジェクトを直接読み取れるようにしたい。これを達成する方法は?

ファイル内のさまざまな位置に書き込む必要があるため、ランダムアクセスファイルを使用する必要がありますまた、オブジェクトが書き込まれた場所を別のデータ構造で記録しています。

4

4 に答える 4

3

ファイル内のさまざまな位置に書き込む必要があるため、ランダムアクセスファイルを使用する必要があります。

いいえ、しません。FileOutputStreamまたはFileInputStreamそのチャネルを介して再配置できます。

これにより、コードの記述も大幅に簡素化されます。バッファーやチャネルを使用する必要はなく、必要に応じて、も省略できますByteArrayOutputStream。ただし、コメントに記載されているように、オブジェクトのサイズは事前にByteArrayOutputStreamわからないため、割り当てられたスペースを超過していないことを確認するのに便利な方法です。

Object obj = // something

FileOutputStream fos = // an initialized stream

ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.flush();

if (bos.size() > MAX_ALLOWED_SIZE)
   throw // or log, or whatever you want to do
else
{
    fos.getChannel().position(writeLocation);
    bos.writeTo(fos);
}

オブジェクトを読み取るには、次の手順を実行します。

FileInputStream fis = // an initialized stream

fis.getChannel().position(offsetOfSerializedObject);
ObjectInputStream iis = new ObjectInputStream(new BufferedInputStream(fis));
Object obj = iis.readObject();

ここに1つのコメント:私はで包みFileInputStreamましたBufferedInputStream。この特定のケースでは、使用するたびにファイルストリームが再配置されるため、パフォーマンスが向上する可能性があります。ただし、バッファリングされたストリームは必要以上のバイトを読み取る可能性があることに注意してください。また、必要に応じて構築するオブジェクトストリームを使用する場合は、非常に悪い考えになる場合があります。

于 2011-09-14T13:31:43.187 に答える
2

なぜあなたのために仕事を求めないのですか?seek()場所を修正してから、オブジェクトストリームを使用してオブジェクトを読み取る必要があると思います。また、シリアル化されたオブジェクトの正しい場所を保存する場合は、それらのサイズを保存してみませんか?この場合ObjectInputStream、ファイルから読み取ったバイトに対して適用できます。

于 2011-09-12T16:52:05.123 に答える
1

頭に浮かぶ最も簡単な解決策は、配列自体を書き出す前に、配列の長さを書き出すことです。

while(rbb.hasRemaining()) {
        fileChannel.writeLong(recordBytes.length);
        fileChannel.write(rbb);
    }

オブジェクトを読み取るときは、最初に長さを読み取ります。これにより、オブジェクトを取得するためにさらに何バイト読み取る必要があるかがわかります。書き込み側ですでに行っていることと同様に、データをaに読み込んでから、andbyte[]を使用できます。ByteArrayInputputStreamObjectInputStream

于 2011-09-12T17:14:38.197 に答える
1

次のように、 'sオブジェクトFileInputStream上に構築されたものを使用できます。RandomAccesFileFileDescriptor

FileDescriptor f = raf.getFD();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));

RandomAccessFileがrafと呼ばれると仮定します。

于 2011-09-12T21:48:27.183 に答える