【问题标题】:What is the proper way to write/read a file with different IO streams用不同的 IO 流写入/读取文件的正确方法是什么
【发布时间】:2011-04-23 13:04:58
【问题描述】:

我有一个包含字节、字符和对象的文件,所有这些都需要先写入然后读取。利用 Java 的不同 IO 流来写入和读取这些数据类型的最佳方法是什么?更具体地说,是否有适当的方法来添加分隔符并识别这些分隔符,然后触发应该使用什么流?我相信我需要澄清在同一个文件中使用多个流,这是我以前从未研究过的。一个彻底的解释将是一个足够的答案。谢谢!

【问题讨论】:

  • 您能否将整个文件作为字节流读取,然后在其中找到您的分隔符,将这些部分放入字节数组中并将它们作为各自的流读取?
  • 这可能会持续到需要读取的对象,但我觉得可能有更直接的方法。

标签: java file-io iostream inputstream outputstream


【解决方案1】:

正如 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

在此处查看非常清晰的示例:ReadWrite

【讨论】:

  • 这是一个很好的例子来说明如何读取和写入对象,但它未能解决我在文件中也有必须与对象区分开来的原语的事实。
  • @Trevor Arjeski - 这正是它所显示的 - 您将原语包装在“MyWrapedData”对象中。我只包括了字符串和字符,但它也可以是任何其他原语。您将包装它们的对象保存在文件中,稍后您读取对象并以相同的方式提取原语。
  • 哦,抱歉,我什至没有看对象。现在我懂了!谢谢
  • 是否可以在 WrappedData 对象中放入一个对象?
  • @Trevor - 当然,就像您将任何其他对象放入类中一样。
【解决方案2】:

重新设计文件。按照目前的设计,没有明智的方法来实现它。例如,该对象预设了一个 ObjectOutputStream,它有一个标头——它会去哪里?你怎么知道在哪里从字节切换到字符?

我可能会为整个事情使用 ObjectOutputStream 并将所有内容都写为对象。然后序列化为您解决所有这些问题。毕竟,您实际上并不关心文件中的内容,而只关心如何读取和写入它。

【讨论】:

  • 所以我将文件中的所有内容都转储为对象,我将如何将其读回?
  • @Trevor Arjeski 使用 writeObject() 写入,使用 readObject() 读取并转换为 byte[]、char[]、您的类等。再简单不过了。
【解决方案3】:

你能改变文件的结构吗?目前尚不清楚,因为您问题的第一句话与能够添加轮廓线相矛盾。如果您可以更改文件结构,您可以将不同的数据类型输出到单独的文件中。我认为这是描述数据流的“正确”方式。

如果您对文件的这种方式感到困惑,那么您将需要为文件结构编写一个接口,这实际上是一个读取操作和大量异常处理的购物清单。一种骇人听闻的编程方式,因为它需要十六进制编辑器和大量试验和错误,但它在某些情况下有效。

【讨论】:

  • 我错了,我确实可以控制文件的结构
【解决方案4】:

为什么不将文件编写为 XML,可能使用 XSTream 之类的简单库。如果您担心空间,请将其包装在 gzip 压缩中。

【讨论】:

    【解决方案5】:

    如果您可以控制文件格式,并且它不是特别大的文件(即

    它们生成解析(和序列化)文件/字节[] 内容的代码。协议缓冲区对包括 (1) 字段编号和 (2) 类型的每个值都使用标记方法,因此它们具有很好的属性,例如与可选字段的向前/向后兼容性等。它们针对速度和文件大小进行了相当好的优化,只为短字节 [] 增加约 2 字节的开销,并在更大的字节 [] 字段(VarInt 编码长度)上增加约 2-4 字节来编码长度。

    这可能有点矫枉过正,但如果你有一堆不同的字段和类型,protobuf 真的很有帮助。请参阅:http://code.google.com/p/protobuf/

    另一种选择是 Facebook 的 Thrift,它支持更多的语言,尽管我上次检查时在野外使用的可能更少。

    【讨论】:

      【解决方案6】:

      如果您的文件结构不固定,请考虑对每种类型使用包装器。首先,您需要创建包装类的接口……。

      接口 MyWrapper 扩展 Serializable { 无效接受(MyWrapperVisitor 访客); }

      然后你创建 MyWrapperVisitor 接口……

      接口 MyWrapperVisitor { 无效访问(MyString 包装器); 无效访问(MyChar 包装器); 无效访问(MyLong 包装器); 无效访问(MyCustomObject 包装器); }

      然后你创建你的包装类…

      类 MyString 实现 MyWrapper { 公共最终字符串值; 公共MyString(字符串值){ 极好的(); this.value = 值; } @覆盖 公共无效接受(MyWrapperVisitor 访问者){ 访客.visit(this); } } . . .

      最后你读到了你的对象……

      final InputStream in = new FileInputStream(myfile); final ObjectInputStream objIn = new ObjectInputStream(in); 最终的 MyWrapperVisitor 访问者 = 新的 MyWrapperVisitor() { @覆盖 公共无效访问(MyString 包装器){ //你的逻辑在这里 } . . . }; //在这里循环你所有的对象 最终 MyWrapper 包装器 = (MyWrapper) objIn.readObject(); wrapper.accept(访客);

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-15
        • 1970-01-01
        • 1970-01-01
        • 2011-11-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-30
        相关资源
        最近更新 更多