如何在Java中读取/编写可序列化对象实例到RandomAccessFile?我想能够像在c ++中通过结构一样做到这一点。在java中只有ObjectInputStreams / ObjectOutputStreamscan可以读/写对象。我很惊讶Java没有已经实现的东西。
答案 0 :(得分:5)
通过ObjectOutputStream将数据写入ByteArrayOutputStream,然后将byte []放入随机访问文件中。你可以用同样的方式做反向。
但是,你为什么要这样做呢?我怀疑有些产品会为你做这些,比如可以持久保存到磁盘的缓存。在这个原因中,您可以只使用一个Map来放置对象,而库可以处理剩下的事情。
答案 1 :(得分:4)
序列化Java对象与使用fwrite写出的C结构之间存在差异:序列化java对象可能没有固定大小(以字节为单位)。
我很惊讶Java没有 已经实施的东西。
确实如此。较新版本的Java附带Java DB,这是一个嵌入式数据库,可以满足您的需求,而且可以提供更多功能。 (请注意,这种类型的数据库基本上是随机访问文件,它们处理数据类型,如字符串和数字而不是字节)。这有一个缺点,你必须编写一些JDBC样板。
如果您不介意包含外部依赖项,那么对象数据库(如db4o)非常有趣并且需要最少的代码。
答案 2 :(得分:4)
我可以看到你为什么要这样做来阅读遗留文件格式。在这种情况下,默认的Java序列化机制是一个障碍,而不是帮助。在某种程度上,你可以使用反射来读/写类似结构的类。
示例代码:
public static class MyStruct {
public int foo;
public boolean bar = true;
public final byte[] byteArray = new byte[3];
}
public static void main(String[] args) throws IOException {
LegacyFileHandler handler = new LegacyFileHandler();
MyStruct struct = new MyStruct();
RandomAccessFile file = new RandomAccessFile("foo", "rw");
try {
for (int i = 0; i < 4; i++) {
struct.foo = i;
handler.write(file, struct);
}
struct = readRecord(file, handler, 2);
System.out.println(struct.foo);
} finally {
file.close();
}
}
private static MyStruct readRecord(RandomAccessFile file,
LegacyFileHandler handler, int n) throws IOException {
MyStruct struct = new MyStruct();
long pos = n * handler.sizeOf(struct);
file.seek(pos);
handler.read(file, struct);
return struct;
}
处理程序类;可以处理原始类型和字节数组,但没有别的:
public class LegacyFileHandler {
private final Map<Class<?>, Method> readMethods = createReadMethodMap();
private final Map<Class<?>, Method> writeMethods = createWriteMethodMap();
private Map<Class<?>, Method> createReadMethodMap() {
Class<DataInput> clazz = DataInput.class;
Class<?>[] noparams = {};
try {
Map<Class<?>, Method> map = new HashMap<Class<?>, Method>();
map.put(Boolean.TYPE, clazz.getMethod("readBoolean", noparams));
map.put(Byte.TYPE, clazz.getMethod("readByte", noparams));
map.put(Character.TYPE, clazz.getMethod("readChar", noparams));
map.put(Double.TYPE, clazz.getMethod("readDouble", noparams));
map.put(Float.TYPE, clazz.getMethod("readFloat", noparams));
map.put(Integer.TYPE, clazz.getMethod("readInt", noparams));
map.put(Long.TYPE, clazz.getMethod("readLong", noparams));
map.put(Short.TYPE, clazz.getMethod("readShort", noparams));
return map;
} catch (NoSuchMethodException e) {
throw new IllegalStateException(e);
}
}
private Map<Class<?>, Method> createWriteMethodMap() {
Class<DataOutput> clazz = DataOutput.class;
try {
Map<Class<?>, Method> map = new HashMap<Class<?>, Method>();
map.put(Boolean.TYPE, clazz.getMethod("writeBoolean",
new Class[] { Boolean.TYPE }));
map.put(Byte.TYPE, clazz.getMethod("writeByte",
new Class[] { Integer.TYPE }));
map.put(Character.TYPE, clazz.getMethod("writeChar",
new Class[] { Integer.TYPE }));
map.put(Double.TYPE, clazz.getMethod("writeDouble",
new Class[] { Double.TYPE }));
map.put(Float.TYPE, clazz.getMethod("writeFloat",
new Class[] { Float.TYPE }));
map.put(Integer.TYPE, clazz.getMethod("writeInt",
new Class[] { Integer.TYPE }));
map.put(Long.TYPE, clazz.getMethod("writeLong",
new Class[] { Long.TYPE }));
map.put(Short.TYPE, clazz.getMethod("writeShort",
new Class[] { Integer.TYPE }));
return map;
} catch (NoSuchMethodException e) {
throw new IllegalStateException(e);
}
}
public int sizeOf(Object struct) throws IOException {
class ByteCounter extends OutputStream {
int count = 0;
@Override
public void write(int b) throws IOException {
count++;
}
}
ByteCounter counter = new ByteCounter();
DataOutputStream dos = new DataOutputStream(counter);
write(dos, struct);
dos.close();
counter.close();
return counter.count;
}
public void write(DataOutput dataOutput, Object struct) throws IOException {
try {
Class<?> clazz = struct.getClass();
for (Field field : clazz.getFields()) {
Class<?> type = field.getType();
if (type == byte[].class) {
byte[] barray = (byte[]) field.get(struct);
dataOutput.write(barray);
continue;
}
Method method = writeMethods.get(type);
if (method != null) {
method.invoke(dataOutput, field.get(struct));
continue;
}
throw new IllegalArgumentException("Type "
+ struct.getClass().getName()
+ " contains unsupported field type " + type.getName()
+ " (" + field.getName() + ")");
}
} catch (IllegalAccessException e) {
throw new IllegalArgumentException(e);
} catch (InvocationTargetException e) {
throw new IllegalStateException(e);
}
}
public void read(DataInput dataInput, Object struct) throws IOException {
try {
Class<?> clazz = struct.getClass();
Object[] noargs = {};
for (Field field : clazz.getFields()) {
Class<?> type = field.getType();
if (type == byte[].class) {
byte[] barray = (byte[]) field.get(struct);
dataInput.readFully(barray);
continue;
}
Method method = readMethods.get(type);
if (method != null) {
Object value = method.invoke(dataInput, noargs);
field.set(struct, value);
continue;
}
throw new IllegalArgumentException("Type "
+ struct.getClass().getName()
+ " contains unsupported field type " + type.getName()
+ " (" + field.getName() + ")");
}
} catch (IllegalAccessException e) {
throw new IllegalArgumentException(e);
} catch (InvocationTargetException e) {
throw new IllegalStateException(e);
}
}
}
此代码仅经过粗略测试。
尝试概括这样的读/写数据存在问题。
如果我需要处理二进制格式,我可能会将这些功能封装在专门的类中,这些类能够在I / O源上写入/读取它们的状态。您仍然会遇到上述列表中的问题,但这是一种更加面向对象的方法。
如果我有自由选择文件格式,我会选择waqas suggested并使用数据库。