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 设备
在使用中阅读:
ByteArrayInputStream
和DataInputStream
dis,和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 读取
来自 OutputStream 的 ByteArrayOutputStream