【问题标题】:How to initialize a ByteBuffer if you don't know how many bytes to allocate beforehand?如果您事先不知道要分配多少字节,如何初始化 ByteBuffer?
【发布时间】:2010-11-26 15:08:09
【问题描述】:

这是:

ByteBuffer buf = ByteBuffer.allocate(1000);

...初始化ByteBuffer的唯一方法?

如果我不知道需要分配多少字节怎么办?

编辑:更多细节:

我正在将一种图像文件格式转换为 TIFF 文件。问题是起始文件格式可以是任意大小,但我需要将 TIFF 中的数据写入小端。所以我正在阅读我最终要打印到 TIFF 文件的内容,首先将其打印到 ByteBuffer 中,这样我就可以将所有内容放入 Little Endian,然后将其写入 outfile。我想既然我知道 IFD 有多长,标头有多长,而且我大概可以算出每个图像平面中有多少字节,我可以在整个过程中使用多个 ByteBuffer。

【问题讨论】:

    标签: java initialization bytebuffer


    【解决方案1】:

    您将使用ByteBuffer 的位置类型通常是您将使用字节数组(也具有固定大小)的位置类型。对于同步 I/O,您通常使用字节数组,而对于异步 I/O,则使用 ByteBuffers。

    如果您需要使用ByteBuffer 读取未知数量的数据,请考虑在缓冲区中使用循环,并在读取数据时将数据附加到ByteArrayOutputStream。完成后,调用toByteArray() 获取最终的字节数组。

    当您不确定给定输入的大小(或最大大小)时,在循环中读取(可能使用ByteArrayOutputStream,否则只是将数据作为流处理,因为它是read) 是处理它的唯一方法。如果没有某种循环,任何剩余的数据当然都会丢失。

    例如:

    final byte[] buf = new byte[4096];
    int numRead;
    
    // Use try-with-resources to auto-close streams.
    try(
      final FileInputStream fis = new FileInputStream(...);
      final ByteArrayOutputStream baos = new ByteArrayOutputStream()
    ) {
      while ((numRead = fis.read(buf)) > 0) {
        baos.write(buf, 0, numRead);
      }
    
      final byte[] allBytes = baos.toByteArray();
    
      // Do something with the data.
    }
    catch( final Exception e ) {
      // Do something on failure...
    }
    

    如果您想编写 Java ints 或其他不是原始字节的东西,您可以将 ByteArrayOutputStream 包装在 DataOutputStream 中:

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    DataOutputStream dos = new DataOutputStream(baos);
    
    while (thereAreMoreIntsFromSomewhere()) {
        int someInt = getIntFromSomewhere();
        dos.writeInt(someInt);
    }
    
    byte[] allBytes = baos.toByteArray();    
    

    【讨论】:

    • 你能举一个使用 ByteArrayOutputStream 的例子吗?比如说一个整数?
    • @PaulaKristin 立即查看(我还修复了损坏的 ByteArrayOutputStream 链接)
    【解决方案2】:

    视情况而定。

    图书馆

    对于大多数问题域来说,转换文件格式往往是一个已解决的问题。例如:

    • Batik可以在各种图像格式(包括TIFF)之间进行转码。
    • Apache POI 可以在 office 电子表格格式之间进行转换。
    • Flexmark 可以从 Markdown 生成 HTML。

    列表很长。第一个问题应该是,“library 可以完成这个任务吗?”如果性能是一个考虑因素,您的时间可能更适合用于优化现有包以满足您的需求,而不是编写另一个工具。 (作为奖励,其他人可以从集中式工作中受益。)


    已知数量

    • 读取文件?分配 file.size() 字节。
    • 复制字符串?分配 string.length() 字节。
    • 复制 TCP 数据包?例如,分配 1500 个字节。

    未知数量

    当字节数确实未知时,你可以做几件事:

    • 猜一猜。
    • 分析示例数据集以缓冲;使用平均长度。

    示例

    Java 的StringBuffer,除非另有说明,使用初始缓冲区大小来容纳 16 个字符。填满 16 个字符后,分配一个新的更长的数组,然后复制原始的 16 个字符。如果 StringBuffer 的初始大小为 1024 个字符,则重新分配不会过早或经常发生。

    优化

    不管怎样,这可能是一个过早的优化。通常,当您想要减少执行的内部内存重新分配的数量时,您会分配一定数量的字节。

    这不太可能成为应用程序的瓶颈。

    【讨论】:

    • StringBuffer 的行为不同。如果您尝试添加更多,ByteBuffer 只会抛出 BufferOverflowException
    【解决方案3】:

    这个想法是它只是一个缓冲区 - 不是整个数据。当您读取一个块并处理它(可能将其写入其他地方)时,它是数据的临时休息点。所以,给自己分配一个足够大的“块”,通常不会有问题。

    您预计会遇到什么问题?

    【讨论】:

      猜你喜欢
      • 2015-01-03
      • 2023-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-25
      相关资源
      最近更新 更多