ByteArrayOutputStream 用于短裤而不是字节

Posted

技术标签:

【中文标题】ByteArrayOutputStream 用于短裤而不是字节【英文标题】:ByteArrayOutputStream for shorts instead of bytes 【发布时间】:2014-03-19 20:05:10 【问题描述】:

我使用了 ByteArrayOutputStream,它非常有用,但对于我的需要来说,限制太大了(即我正在处理 +-32,768 范围内的数字)

这是我将使用它的代码:

ByteArrayOutputStream leftStream = new ByteArrayOutputStream();
ByteArrayOutputStream rightStream = new ByteArrayOutputStream();

while (din.read(temp, 0, 4) != -1) 
    if (decodedFormat.getChannels() == 2) 
       leftStream.write(temp[1] * 256 + temp[0]);
       rightStream.write(temp[3] * 256 + temp[2]);
    


byte[] left = leftStream.toByteArray();
byte[] right = rightStream.toByteArray();

但是 ByteArrayInputStream 不允许超过 127 或低于 128 的值。是否有等效的 ShortArrayOutputStream 允许短裤?还是我必须自己制作一个?

【问题讨论】:

使用 ByteBuffer 并调用 ByteBuffer.getShort 【参考方案1】:

是的,使用 DataOutputStream:

ByteArrayOuputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);

dos.writeShort(val);

这甚至适用于 Java 版本 1.3 较低的嵌入式 Java 设备

在使用中阅读:

ByteArrayInputStreamDataInputStreamdis,和dis.readShort()

...
byte[] bytes = bos.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
DataInputStream dis = new DataInputStream(bis);
short val = dis.readShort();

【讨论】:

谢谢,如果我写的短裤的值大于 128,那么 toByteArray 肯定不会让这些短裤通过? 一个short在java中是2byte:java中从-32767到32768。所以你写出来的东西,就是读入的。你必须按照你写它的顺序来读它。如果都是短裤就好了。您可以将字节与 short 和 int 混合,但在读入时使用 smae 顺序。 嗯明白了,我会努力实现的 写一个单元测试用例,你会很容易看到你得到了什么。【参考方案2】:

您可以将ByteArrayOutputStream 包装成DataOutputStream

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);

dataOutputStream.writeShort(someShortValue);

【讨论】:

如何从该流中检索 short[] 数组?喜欢一些toShortArray() 方法? @Cobbles 当然带有 readShort(),但来自 DataInputStream() @Cobbles 你会在另一边看到DataInputStream @AlexWien,partlov 如何从 dataOutputStream 中获取 InputStream? 我不确定你的用例是什么。如果您通过网络传输数组,您将获得输入流。【参考方案3】:

你想做什么?

将短数据写入字节数组?

然后用 DataOutputStream 包装您的字节数组输出流,该流具有 writeShort()、writeInt() 等方法。警告。我认为 DataOutputStream 的 endian 是 BIG endian,所以如果你想使用 little endian,你要么自己写,要么使用其他选项:

ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
DataOutputStream dataout = new DataOutputStream(byteOut)

dataout.writeShort(shortValue);

写一篇短文[]

最简单的方法是创建一个ByteBuffer,然后使用asShortBuffer() 方法将其视为一个ShortBuffer。 ShortBuffer 有一个 put(short) 和 put(short[]);

如果你想用Little endian写出短数据,ByteBuffer有一个方法asOrder(ByteOrder)可以改变它正在读取或写入的数据的字节序。

//NOTE length should be 2* num shorts since we allocate in bytes
ByteBuffer buf = ByteBuffer.allocate(length);

ShortBuffer shortBuf = buf.asShortBuffer();
shortBuf.put(shortValue);
shortBuf.put(shortArray);

从缓冲区中取出数据很烦人。有可选的 array() 方法,但并非所有缓冲区实现都支持它们,因此您必须执行以下操作:

//once all data written to buffer
shortBuf.flip();
short[] dataOut = new short[shortBuf.remaining()];
shortBuf.get(dataOut);

两者结合使用 ShortBuffer 处理未知的输入大小

如果您不知道要写入多少字节,并且没有合理的最大长度,那么您可能需要结合使用这两个选项。首先,使用选项#1 通过向字节缓冲区写入短裤来动态增长字节缓冲区。然后使用 ShortBuffer 将 byte[] 转换为 short[]。

 ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
DataOutputStream dataout = new DataOutputStream(byteOut)

dataout.writeShort(shortValue);
...

ShortBuffer buf =ByteBuffer.wrap(byteOut.toByteArray())
                           .asShortBuffer();

int length = buf.remaining();
short[] asShorts = new short[length];
buf.get(asShorts);

因为你复制了一个数组,所以它不漂亮并且使用了 2 倍的内存。

【讨论】:

你能发布一个如何使用第二个选项的例子吗? 这不是最简单的选择。但在 PC 上比 dataOutputStream 解决方案快得多。小端和大端从来都不是他问题的重点 @dkatzel 例如谢谢,但我使用流的原因是因为我不知道我之前会使用多少字节,那么我该如何计算长度? @Cobbles 添加了更多代码来解释一种方法。 我不会这样做,但对于这个过于复杂的解决方案,我会重新添加 -1。但是,当需要以更高的开发成本获得最大性能时,这是一个非常快速的解决方案。【参考方案4】:

创建一个 ObjectOutputStream。这有一个 writeShort (http://docs.oracle.com/javase/7/docs/api/java/io/ObjectOutputStream.html#writeShort(int)) 方法。

ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeShort(123);
...

【讨论】:

Object OutputStream 太过分了,因为它应该用于序列化对象而不是写出原始数组 它使用了大量的存储空间,而且速度非常慢。

以上是关于ByteArrayOutputStream 用于短裤而不是字节的主要内容,如果未能解决你的问题,请参考以下文章

JAVA IO流相关代码(ByteArrayInputStream类和ByteArrayOutputStream类相关代码)

在写入时从 ByteArrayOutputStream 读取

从 ByteArrayOutputStream 创建文件

来自 OutputStream 的 ByteArrayOutputStream

用ByteArrayOutputStream解决IO流乱码问题

java:ByteArrayOutputStream.toByteArray()性能