【问题标题】:Can I manipulate mixed text/binary data in the same file using Java?我可以使用 Java 操作同一文件中的混合文本/二进制数据吗?
【发布时间】:2013-12-20 04:27:43
【问题描述】:

据我了解,Java 中有两种类型的文件 I/O api。
面向文本和面向二进制。
我无法理解的是,当我们想要创建一个混合了文本和二进制数据的文件时,我们会使用什么。
例如。将可变长度记录保存在文件中的一个简单案例,其中每条记录(Unicode 文本)都有 2 个字节 (short) 的整数,用于指定记录的大小。
这可能吗?或者我只能操作单一类型的文件?纯文本还是纯二进制?

【问题讨论】:

标签: java file io inputstream


【解决方案1】:

没有混合,一切都是二进制的,你只需要知道如何处理字节。只需读取字节并决定如何处理它们。

而且您可能需要超过两个字节来包含大小,因为您还必须知道要读取的信息是什么。所以你需要知道大小和类型才能正确读取。

你可能会得到类似的结果:

0      1        3                  (4 + length)
+------+--------+------------------------+
| Type | Length | Actual message content |
+------+--------+------------------------+

【讨论】:

  • 我不明白这一点。如果我在我的应用程序中创建一个可变长度记录文件,并且我做出设计决定,即 2 字节整数足以满足每条记录的大小;更多每条记录都包含 unicode 文本。这些信息(即 2 字节二进制整数的大小 + unicode 文本)将如何写入/读取文件?
  • 你必须自己写代码来做,就像你写代码来写它一样,你需要写代码来读它。代码没有神奇的方式可以理解你想要什么并为你做。或者你也可以像上面提到的那样使用DataOutputStream
【解决方案2】:

文本用二进制数据表示,所以没有什么能阻止你混合它们。例如,您可以将 Java 对象写入文件,而 Java 对象包含文本。

您所说的区别实际上是可以围绕输入/输出流放置的各种包装器,它们会将文本行或二进制对象的结构放入输入或输出流中。

因此,如果您在输出流周围使用二进制包装器,则可以将文本写入二进制数据。

您必须在输入和输出流上创建自己的包装器,以便将二进制字节或数据流正确解释为二进制和文本数据。

我建议您使用一个类,该类允许您创建包含文本数据的对象,并使用对象输入和对象输出包装器让 Java 运行时为您解决所有问题。

reading and writing serializable objects 上查看这篇文章。

还有这个article about object streams

还有这个article on serializing object has pictures

【讨论】:

  • 我对将文本写成二进制数据不感兴趣。但是将二进制数据和 unicode 文本混合写入同一个文件。查看我对毛里西奥答案的评论
  • @Jim,您似乎不理解的是,它都是二进制数据,并且您对二进制数据施加了特定的结构。您似乎想要将可变长度的文本字符串写入文件,其中文件内容是一组对象,这些对象由长度字段后跟零个或多个 UNICODE 字符组成。这是一个已经被反复解决的问题,而且并不新鲜。
  • This is a problem that has been addressed over and over again and it is not new我没有说或认为这是一个新问题。我问热它是使用Java解决的
【解决方案3】:

由于字符是“由”字节组成的,您可以使用二进制 API (OutputStream) 来同时编写二进制和基于文本的数据。例如:

try (OutputStream out = new FileOutputStream(file)) {
    out.write(recordSizeFirstByte);
    out.write(recordSizeSecondByte);
    out.write(stringData.getBytes("UTF-8"));
}

说明:这将首先写入两个字节,然后写入字符数据,使用UTF-8 编码。

【讨论】:

    【解决方案4】:

    当然,所有内容都存储为字节,当然您可以使用任何二进制阅读器读取它,但这里重要的是处理数据是多么容易。

    当您以文本数据的形式执行文件 I/O 时,您无需处理编码、特定于平台的标准(如换行符)以及涉及解释您正在读入的字节的其他事情,从而为您省去了很多麻烦。

    当您以二进制模式阅读时,您实际上并没有为您处理任何这些便利。您可以阅读 0x0A 0x0D 并将其解释为单独的字节,但如果没有上下文(换行 + 回车),谁会真正知道它们代表什么

    当我说一个文件包含“文本数据”或者它是一个“文本文件”时,我通常是指您可以使用特定的编码来读取它,因此“混合”文本和二进制文件的文件变得有点困难,因为如果你假设它是文本数据,你的程序可能会在应该被视为二进制数据的字节上崩溃(例如:一个整数的两个字节,而不是将它转换为你使用的任何编码的字符)

    完全可以创建这样的文件,但是您必须以二进制模式执行文件 I/O 并保持一致(并希望输入的任何输入都可以转换为您决定使用的任何格式) .虽然从 cmets 看来,DataOutputStream 对您来说更容易一些。

    【讨论】:

    • 但是如果我把字符串写成二进制不能读回来,那就没什么用了...
    • 使用文本编写器编写的字符串和使用二进制编写器编写的字符串并没有什么特别之处。它们最终是相同的字节。不同之处在于,实际写入的字节可能因文本编写器的设置而异(例如:用二进制编写器写出“a”可能是0x61,但文本编写器可能会写成0x61 0x00)。您只需要确保您的阅读和写作始终如一。如何从文件中读取完全取决于您(但如果混合使用文本和二进制,则必须将其全部作为二进制数据读取)
    • 我希望我没有让您混淆我所说的为什么人们可能更喜欢使用文本阅读器/编写器。只是,IMO,使用文本阅读器处理严格表示文本的二进制数据要容易得多,因为如果文本阅读器遇到代表浮点数的 4 个字节,它不会将其读取为浮点数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多