我有一个包含字节、字符和对象的文件,所有这些都需要先写入然后再读取。利用 Java 的不同 IO 流来写入和读取这些数据类型的最佳方法是什么?更具体地说,是否有适当的方法来添加分隔符并识别这些分隔符,然后触发应该使用什么流?我相信我需要对在同一个文件中使用多个流进行一些澄清,这是我以前从未研究过的。一个彻底的解释将是一个足够的答案。谢谢!
6 回答
正如EJP已经建议的那样,使用 ObjectOutputStream 和 ObjectInputStream an0d 将您的其他元素包装为一个对象。我给出一个答案,所以我可以举一个例子(在评论中很难做到)EJP - 如果你想将它嵌入你的问题,请这样做,我会删除答案。
class MyWrapedData implements serializeable{
private String string1;
private String string2;
private char char1;
// constructors
// getters setters
}
写入文件:
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName));
out.writeObject(myWrappedDataInstance);
out.flush();
从文件中读取
ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName));
Object obj = in.readObject();
MyWrapedData wraped = null;
if ((obj != null) && (obj instanceof MyWrappedData))
wraped = (MyWrapedData)obj;
// get the specific elements from the wraped object
重新设计文件。没有明智的方式来按照目前的设计来实现它。例如,该对象预设了一个 ObjectOutputStream,它有一个标头 - 它将去哪里?你怎么知道在哪里从字节切换到字符?
我可能会为整个事情使用 ObjectOutputStream 并将所有内容都写为对象。然后序列化为您解决所有这些问题。毕竟,您实际上并不关心文件中的内容,而只关心如何读取和写入它。
你能改变文件的结构吗?目前尚不清楚,因为您问题的第一句话与能够添加轮廓线相矛盾。如果您可以更改文件结构,您可以将不同的数据类型输出到单独的文件中。我认为这是描述数据流的“正确”方式。
如果您坚持使用文件的方式,那么您将需要为文件结构编写一个接口,这实际上是一个读取操作和大量异常处理的购物清单。一种骇人听闻的编程方式,因为它需要一个十六进制编辑器和大量的试验和错误,但它在某些情况下有效。
为什么不将文件编写为 XML,可能使用 XSTream 之类的简单库。如果您担心空间,请将其包装在 gzip 压缩中。
如果您可以控制文件格式,并且它不是特别大的文件(即 < 1 GiB),您是否考虑过使用 Google 的协议缓冲区?
它们生成解析(和序列化)文件/字节[]内容的代码。协议缓冲区对包括 (1) 字段编号和 (2) 类型的每个值都使用标记方法,因此它们具有很好的属性,例如与可选字段的向前/向后兼容性等。它们针对速度和文件大小进行了相当好的优化,为短字节 [] 仅增加约 2 个字节的开销,并增加约 2-4 个字节来对较大的 byte[] 字段的长度进行编码(VarInt 编码长度)。
这可能有点矫枉过正,但如果你有一堆不同的字段和类型,protobuf 真的很有帮助。请参阅:http ://code.google.com/p/protobuf/ 。
另一种选择是 Facebook 的 Thrift,它支持更多的语言,尽管我上次检查时在野外使用的可能更少。
如果文件的结构不固定,请考虑对每种类型使用包装器。首先,您需要创建包装类的接口……。
接口 MyWrapper 扩展 Serializable { 无效接受(MyWrapperVisitor 访客); }
然后创建 MyWrapperVisitor 接口……</p>
接口 MyWrapperVisitor { 无效访问(MyString 包装器); 无效访问(MyChar 包装器); 无效访问(MyLong 包装器); 无效访问(MyCustomObject 包装器); }
然后你创建你的包装类......</p>
类 MyString 实现 MyWrapper { 公共最终字符串值; 公共MyString(字符串值){ 极好的(); this.value = 值; } @覆盖 公共无效接受(MyWrapperVisitor 访问者){ 访客.visit(this); } } . . .
最后你阅读了你的对象……</p>
final InputStream in = new FileInputStream(myfile); final ObjectInputStream objIn = new ObjectInputStream(in); 最终的 MyWrapperVisitor 访问者 = 新的 MyWrapperVisitor() { @覆盖 公共无效访问(MyString 包装器){ //你的逻辑在这里 } . . . }; //在这里循环你所有的对象 最终 MyWrapper 包装器 = (MyWrapper) objIn.readObject(); wrapper.accept(访客);