你好男孩和女孩。
我正在开发一个基于终端的客户端应用程序,它通过TCP / IP与服务器通信,并发送和接收任意数量的原始字节。每个字节代表一个命令,我需要将其解析为表示这些命令的Java类,以供进一步使用。
我的问题是如何有效地解析这些字节。我不想最终得到一堆嵌套的ifs和switch-cases。
我准备好了这些命令的数据类。我只需要找出解析的正确方法。
以下是一些示例规范:
字节流可以是例如 整数:[1,24,2,65,26,18,3,0,239,19,0,14,0,42,65,110,110,97,32,109,121,121,106,228,42,15,20,5,149,45,87]
第一个字节是0x01,它是仅包含一个字节的标头的开头。
第二个是长度,它是特定的字节数 命令,这里也只有一个字节。
下一个可以是第一个字节是命令0x02的任何命令 在这种情况下,它遵循包含在其中的n个字节 命令。
等等。最后有校验和相关的字节。
表示set_cursor命令的示例类:
/**
* Sets the cursor position.
* Syntax: 0x0E | position
*/
public class SET_CURSOR {
private final int hexCommand = 0x0e;
private int position;
public SET_CURSOR(int position) {
}
public int getPosition() {
return position;
}
public int getHexCommnad() {
return hexCommand;
}
}
答案 0 :(得分:2)
在解析像这样的字节流时,最好使用的设计模式是命令模式。每个不同的命令都将充当处理程序来处理流中的下几个字节。
interface Command{
//depending on your situation,
//either use InputStream if you don't know
//how many bytes each Command will use
// or the the commands will use an unknown number of bytes
//or a large number of bytes that performance
//would be affected by copying everything.
void execute(InputStream in);
//or you can use an array if the
//if the number of bytes is known and small.
void execute( byte[] data);
}
然后,您可以为每个字节“操作码”创建一个包含每个Command对象的映射。
Map<Byte, Command> commands = ...
commands.put(Byte.parseByte("0x0e", 16), new SetCursorCommand() );
...
然后您可以解析消息并对命令执行操作:
InputStream in = ... //our byte array as inputstream
byte header = (byte)in.read();
int length = in.read();
byte commandKey = (byte)in.read();
byte[] data = new byte[length]
in.read(data);
Command command = commands.get(commandKey);
command.execute(data);
您可以在同一个字节消息中有多个命令吗?如果是这样,您可以轻松地将Command获取和解析包装在一个循环中直到EOF。
答案 1 :(得分:2)
您可以为https://github.com/raydac/java-binary-block-parser
尝试JBBP库@Bin class Parsed { byte header; byte command; byte [] data; int checksum;}
Parsed parsed = JBBPParser.prepare("byte header; ubyte len; byte command; byte [len] data; int checksum;").parse(theArray).mapTo(Parsed.class);
答案 2 :(得分:1)
这是一个庞大而复杂的主题。
这取决于您将要阅读的数据类型。
我最近为专有软件编写了一个字节序列化/反序列化库。
我采用类似访问者的方式进行类型转换,就像JAXB的工作方式一样。
我将对象定义为Java类。在类上初始化解析器,然后将字节传递给unserialize或将Java对象传递给序列化。
类型检测(基于流程的第一个字节)通过简单的大小写匹配机制向前完成(1 =&gt; ClassA,15 =&gt; ClassF,...)。
编辑:代码(嵌入对象)可能很复杂或过载,但请记住,现在,java很好地优化了它,它使代码清晰易懂。答案 3 :(得分:0)
ByteBuffer
can be used for parsing byte stream - What is the use of ByteBuffer in Java?:
byte[] bytesArray = {4, 2, 6, 5, 3, 2, 1};
ByteBuffer bb = ByteBuffer.wrap(bytesArray);
int intFromBB = bb.order(ByteOrder.LITTLE_ENDIAN).getInt();
byte byteFromBB = bb.get();
short shortFromBB = bb.getShort();