Java 如果事先不知道要分配多少字节,如何初始化 ByteBuffer?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1396016/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 11:38:37  来源:igfitidea点击:

How to initialize a ByteBuffer if you don't know how many bytes to allocate beforehand?

javainitializationbytebuffer

提问by Tony Stark

Is this:

这是:

ByteBuffer buf = ByteBuffer.allocate(1000);

...the only way to initialize a ByteBuffer?

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

What if I have no idea how many bytes I need to allocate..?

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

Edit:More details:

编辑:更多细节:

I'm converting one image file format to a TIFF file. The problem is the starting file format can be any size, but I need to write the data in the TIFF to little endian. So I'm reading the stuff I'm eventually going to print to the TIFF file into the ByteBuffer first so I can put everything in Little Endian, then I'm going to write it to the outfile. I guess since I know how long IFDs are, headers are, and I can probably figure out how many bytes in each image plane, I can just use multiple ByteBuffers during this whole process.

我正在将一种图像文件格式转换为 TIFF 文件。问题是起始文件格式可以是任何大小,但我需要将 TIFF 中的数据写入小端。所以我正在阅读我最终要打印到 TIFF 文件到 ByteBuffer 的东西,这样我就可以把所有东西都放在 Little Endian 中,然后我要把它写到输出文件中。我想因为我知道 IFD 的长度、标题的长度,并且我大概可以算出每个图像平面中有多少字节,所以我可以在整个过程中使用多个 ByteBuffer。

采纳答案by Dave Jarvis

Depends.

要看。

Library

图书馆

Converting file formats tends to be a solved problem for most problem domains. For example:

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

  • Batikcan transcode between various image formats (including TIFF).
  • Apache POIcan convert between office spreadsheet formats.
  • Flexmarkcan generate HTML from Markdown.
  • Batik可以在各种图像格式(包括 TIFF)之间进行转码。
  • Apache POI可以在办公电子表格格式之间进行转换。
  • Flexmark可以从 Markdown 生成 HTML。

The list is long. The first question should be, "What librarycan accomplish this task?" If performance is a consideration, your time is likely better spent optimising an existing package to meet your needs than writing yet another tool. (As a bonus, other people get to benefit from the centralised work.)

名单很长。第一个问题应该是,“什么图书馆可以完成这个任务?” 如果性能是一个考虑因素,与编写另一个工具相比,您的时间可能最好花在优化现有包以满足您的需求上。(作为奖励,其他人可以从集中工作中受益。)



Known Quantities

已知数量

  • Reading a file? Allocate file.size()bytes.
  • Copying a string? Allocate string.length()bytes.
  • Copying a TCP packet? Allocate 1500 bytes, for example.
  • 读取文件?分配file.size()字节。
  • 复制字符串?分配string.length()字节。
  • 复制 TCP 数据包?例如,分配 1500 个字节。

Unknown Quantities

未知数量

When the number of bytes is truly unknown, you can do a few things:

当字节数确实未知时,您可以执行以下操作:

  • Make a guess.
  • Analyze example data sets to buffer; use the average length.
  • 做一个猜想。
  • 分析要缓冲的示例数据集;使用平均长度。

Example

例子

Java's StringBuffer, unless otherwise instructed, uses an initial buffer size to hold 16 characters. Once the 16 characters are filled, a new, longer array is allocated, and then the original 16 characters copied. If the StringBufferhad an initial size of 1024 characters, then the reallocation would not happen as early or as often.

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

Optimization

优化

Either way, this is probably a premature optimization. Typically you would allocate a set number of bytes when you want to reduce the number of internal memory reallocations that get executed.

无论哪种方式,这都可能是过早的优化。通常,当您想要减少执行的内部内存重新分配的数量时,您会分配一定数量的字节。

It is unlikely that this will be the application's bottleneck.

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

回答by Jon Skeet

The idea is that it's only a buffer- not the whole of the data. It's a temporary resting spot for data as you read a chunk, process it (possibly writing it somewhere else). So, allocate yourself a big enough "chunk" and it normally won't be a problem.

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

What problem are you anticipating?

您预计会遇到什么问题?

回答by Adam Batkin

The types of places that you would use a ByteBufferare generally the types of places that you would otherwise use a byte array (which also has a fixed size). With synchronous I/O you often use byte arrays, with asynchronous I/O, ByteBuffers are used instead.

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

If you need to read an unknown amount of data using a ByteBuffer, consider using a loopwith your buffer and append the data to a ByteArrayOutputStreamas you read it. When you are finished, call toByteArray()to get the final byte array.

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

Any time when you aren't absolutely sure of the size (or maximum size) of a given input, reading in a loop (possibly using a ByteArrayOutputStream, but otherwise just processing the data as a stream, as it is read) is the only way to handle it. Without some sort of loop, any remaining data will of course be lost.

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

For example:

例如:

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...
}

If you instead wanted to write Java ints, or other things that aren't raw bytes, you can wrap your ByteArrayOutputStreamin a DataOutputStream:

如果您想编写 Javaint或其他非原始字节的内容,您可以将您ByteArrayOutputStream的内容包装在 a 中DataOutputStream

ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);

while (thereAreMoreIntsFromSomewhere()) {
    int someInt = getIntFromSomewhere();
    dos.writeInt(someInt);
}

byte[] allBytes = baos.toByteArray();