我正在研究Java文件I / O接口,我需要我的文件是二进制格式,而不是字符串。我发现ObjectOutputStream和ObjectInputStream对我的需求很有用,但我需要接口能够在我的文件末尾写入,因为我需要它来反复记录同一文件中的未来数据。
我尝试使用FileOutputStream(String file,boolean append)构造函数,但由于我的类实现了Serializable,因此似乎存在问题。当它尝试读取第二条记录时,会抛出 StreamCorruptedException 。我知道这一定是因为这个标题那种描述了对象的字段。
我的问题是,如何成功存储对象?我喜欢使用对象,因为它可以更容易地构造和处理数据。到目前为止,这是我的代码:
try
{
FileOutputStream outFile;
ObjectOutputStream outStream;
FileInputStream inFile;
ObjectInputStream inStream;
outFile = new FileOutputStream("people.mcf", true);
outStream = new ObjectOutputStream(outFile);
//Writing the objects
System.out.println("Writing file...");
for(int i = 0; i < 3; i++)
{
outStream.writeObject(people[i]);
}
System.out.println("Finished writing file...");
outFile.close();
outStream.close();
//Reading the files
System.out.println("Attempting to read file...");
inFile = new FileInputStream("people.mcf");
inStream = new ObjectInputStream(inFile);
Person buffer;
while(true)
{
buffer = (Person)inStream.readObject();
System.out.println(buffer.getData());
}
}
catch(EOFException e)
{
System.out.println("Reached end of file...");
}
catch(IOException e)
{
System.err.println(e.toString());
}
这是Person类:
static class Person implements Serializable
{
private final String name;
private final int age;
private final String address;
public Person(String name, int age, String address)
{
this.name = name;
this.age = age;
this.address = address;
}
public String getData()
{
return name + " " + age + " " + address;
}
}
这是我得到的输出:
Writing file...
Finished writing file...
Attempting to read file...
Andres 26 Palo Gordo
Pilar 22 Palo Gordo
Kelvin 27 Palo Gordo
java.io.StreamCorruptedException: invalid type code: AC
BUILD SUCCESSFUL (total time: 0 seconds)
编辑:我不知道为什么我收到StreamCorruptedException,我知道ObjectOutputStream导致了这一点,我要求的是另一种存储对象数据的方法结构化的方式。
答案 0 :(得分:0)
如果您的记录是固定长度或至少是MAXIMUM长度,则以下代码可以完成此任务。
使用RandomAccessFile,您将能够搜索文件指针以写入新内容,或更新已存在的记录。请参阅Indexed File in Wikipedia。
为了更加轻松,您可以使用已ByteBuffer已经使用的FileChannel序列化记录,RandomAccessFile.getChannel()是RandomAccessFile的接口,请参阅{{3}}。
代码示例:
重新审视人员课程:
import java.nio.ByteBuffer;
import java.util.UUID;
public class Person implements ISerializable<UUID> {
private final UUID _id;
private final String _name;
private final int _age;
private final String _address;
public Person( ByteBuffer source ) {
_id = SerializeUtil.unserializeUUID( source );
_name = SerializeUtil.unserializeString( source );
_age = source.get();
_address = SerializeUtil.unserializeString( source );
}
public Person( String name, int age, String address) {
_id = UUID.randomUUID();
_name = name;
_age = age;
_address = address;
}
@Override
public UUID getKey() {
return _id;
}
@Override
public void serialize( ByteBuffer target ) {
target.clear();
SerializeUtil.serializeUUID ( _id , target );
SerializeUtil.serializeString( _name , target );
target.put((byte)_age );
SerializeUtil.serializeString( _address, target );
}
}
IndexFile类:
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Consumer;
import java.util.function.Function;
public class IndexedFile<K extends Comparable<K>, R extends ISerializable<K>>
implements
Closeable
{
private final Map<K, Long> _index = new TreeMap<>();
private final RandomAccessFile _file;
private final FileChannel _channel;
private final ByteBuffer _record;
private final Function<ByteBuffer, R> _factory;
public IndexedFile( File tracksFile, int recordSize, Function<ByteBuffer, R> factory ) throws IOException {
_file = new RandomAccessFile( tracksFile, "rw" );
_channel = _file.getChannel();
_record = ByteBuffer.allocate( recordSize );
_factory = factory;
_channel.truncate( 0 );
}
@Override
public void close() throws IOException {
_file.close();
_channel.close();
}
public int size() {
return _index.size();
}
public int recordSize() {
return _record.capacity();
}
public void put( R record ) throws IOException {
final K key = record.getKey();
final Long offset = _index.get( key );
if( offset != null ) {
_channel.position( offset );
}
else {
final long pos = _channel.size();
_channel.position( pos );
_index.put( key, pos );
}
record.serialize( _record );
_record.position( _record.limit());
_record.flip();
_channel.write( _record );
}
public R read( int recNo ) throws IOException {
if( recNo >= _index.size()) {
return null;
}
final long offset = recNo*_record.capacity();
_channel.position( offset );
_record.clear();
_channel.read( _record );
_record.flip();
return _factory.apply( _record );
}
public R get( K key ) throws IOException {
final Long offset = _index.get( key );
if( offset == null ) {
return null;
}
_channel.position( offset );
_record.clear();
_channel.read( _record );
_record.flip();
return _factory.apply( _record );
}
}
为了完整性,实用程序类:
import java.nio.ByteBuffer;
import java.util.UUID;
public final class SerializeUtil {
public static void serializeString( String s, ByteBuffer target ) {
final byte[] bytes = s.getBytes();
target.putInt( bytes.length );
target.put( bytes );
}
public static String unserializeString( ByteBuffer target ) {
final int length = target.getInt();
final byte[] bytes = new byte[length];
target.get( bytes );
return new String( bytes );
}
public static void serializeUUID( UUID id, ByteBuffer target ) {
target.putLong( id.getMostSignificantBits());
target.putLong( id.getLeastSignificantBits());
}
public static UUID unserializeUUID( ByteBuffer source ) {
final long msb = source.getLong();
final long lsb = source.getLong();
return new UUID( msb, lsb );
}
}
接口ISerializable:
import java.nio.ByteBuffer;
public interface ISerializable<K extends Comparable<K>> {
public K getKey();
public void serialize( ByteBuffer target );
}