如何将混合 Java 数据类型转换为 Java 字节数组?

How do I convert mixed Java data types into a Java byte array?

我需要用混合数据类型构造一个 Java 字节数组,但我不知道该怎么做。这些是我的类型:

byte version = 1; // at offset 0
short message_length = // the size of the byte[] message I am constructing here, at offset 1
short sub_version = 15346; // at offset 3
byte message_id = 2; // at offset 5
int flag1 = 10; // at offset 6
int flag2 = 0; // at offset 10
int flag3 = 0; // at offset 14
int flag4 = 0; // at offset 18
String message = "the quick brown fox jumps over the lazy dog"; // at offset 22

我知道字符串,我可以使用

message.getBytes("US_ASCII");

我知道 int 值,我可以使用

Integer.byteValue();

我知道短值,我可以使用

Short.byteValue();

而且字节值已经是字节,我只是不确定如何将所有这些组合成一个字节数组。我读过

System.arraycopy();

这是正确的过程吗,我只是将所有数据转换为字节,然后用 arraycopy 开始 "concatenating" 字节数组?

我正在与一些我无法控制的远程服务器通信,这是他们需要的消息处理。

如果 'mixed type' 是指具有不同成员字段类型的 class,那么一种方法是使 class serializable,并使用 ApacheUtils

byte[] data = SerializationUtils.serialize(yourObject);

当然,您可以按照您的建议将这些值与 arrayCopy 连接起来。

您还可以将字节附加到 ByteArrayOutputStream

关键是要准确理解接收系统的期望。它如何知道一个字段在哪里结束,下一个字段从哪里开始?它如何知道它在流中给定位置读取的是什么类型?他们可以选择很多方法来做到这一点——协议中的长度为 headers;类型为 headers; null-termination 个字符串;具有一组字段顺序及其长度;等等。

无论您选择什么方法,编写单元测试来检查负数、非常大的数字、non-ASCII 文本等边缘情况。当一切正常时很容易被刺痛,然后服务器突然阻塞在一个 Unicode 字符或一个它解释为非常大的数字的负数上。

另一种选择——可能对您的需求有点矫枉过正,但灵活且具有高性能——是 Google 的 protocol buffers 库。

DataOutputStream 包裹在 ByteArrayOutputStream 周围。这样你就可以将所有原始类型如 intshort 直接写入 DataOutputStream,后者将它们转换为字节并将它们转发到 ByteArrayOutputStream,从中你可以然后将整个事物作为一个字节数组检索:

ByteArrayOutputStream bOut = new ByteArrayOutputStream();
DataOutputStream dOut = new DataOutputStream(bOut);

dOut.writeByte(version);
dOut.writeShort(message_length);
dOut.writeShort(sub_version);
dOut.writeByte(message_id);
dOut.writeInt(flag1);
dOut.writeInt(flag2);
dOut.writeInt(flag3);
dOut.writeInt(flag4);
dOut.write(message.getBytes(), 0, message.length());

dOut.flush();
byte[] result = bOut.toByteArray();

关于此的最好的事情是您可以使用 DataInputStreamByteArrayInputStream 完全类似于上面的代码来执行完全相反的操作(从字节数组中提取值)。

所有,我想 post 我自己的解决方案来解决我的问题。我在 how to insert a short into java byte array. One of the results talked about a Java ByteBuffer 上进行了快速 Google 搜索。阅读之后,我确定这是获得所需结果的最佳和最快方式。 Java API 中真正让我对 ByteBuffer 感兴趣的部分是:

Methods in this class that do not otherwise have a value to return are specified to return the buffer upon which they are invoked. This allows method invocations to be chained. The sequence of statements

bb.putInt(0xCAFEBABE);
bb.putShort(3);
bb.putShort(45);

can, for example, be replaced by the single statement

bb.putInt(0xCAFEBABE).putShort(3).putShort(45);

所以,这就是我所做的:

byte version = 1;
short message_length = 72;
short sub_version = 15346;
byte message_id = 2;
int flag1 = 10;
int flag2 = 0;
int flag3 = 0;
int flag4 = 0;
String message = "the quick brown fox jumps over the lazy dog";
ByteBuffer messageBuffer = ByteBuffer.allocate(message_length);

messageBuffer.put(version).putShort(message_length).putShort(sub_version).put(message_id).putInt(flag1).putInt(flag2).putInt(flag3).putInt(flag4).put(message.getBytes());

byte[] myArray = messageBuffer.array();

这既快速又简单,正是我所需要的。感谢所有花时间阅读和回复的人。