如何在 Java 中正确解析字节流



你好男孩和女孩。

我正在开发一个基于终端的客户端应用程序,它通过TCP/IP与服务器通信,并发送和接收任意数量的原始字节。每个字节代表一个命令,我需要将其解析为表示这些命令的 Java 类,以供进一步使用。

我的问题应该如何有效地解析这些字节。我不想以一堆嵌套的 if 和开关案例结束。

我已经准备好了这些命令的数据类。我只需要找出正确的解析方法。

下面是一些示例规格:

字节流可以是例如 整数:[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;
}
}

像这样解析字节流时,最好的设计模式是命令模式。 每个不同的命令将充当处理程序来处理流中接下来的几个字节。

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);
}

然后,您可以拥有一个映射,其中包含每个字节"操作码"的每个命令对象。

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);

您可以在同一字节消息中有多个命令吗? 如果是这样,您可以轻松地将命令获取和解析包装在一个循环中,直到 EOF。

你可以试试JBBP库来 https://github.com/raydac/java-binary-block-parser

@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);

这是一个庞大而复杂的主题。

这取决于您将读取的数据类型。

  • 是一条嘻嘻哈哈的溪流吗?
  • 是很多小的独立结构/对象吗?
  • 您的流的结构/对象之间是否有一些引用?

我最近为一个专有软件编写了一个字节序列化/反序列化库。

我采用了类似访问者的类型转换方法,与 JAXB 的工作方式相同。

我将我的对象定义为 Java 类。 初始化类上的解析器,然后向其传递要取消序列化的字节或要序列化的 Java 对象。

类型检测(基于流的第一个字节)通过简单的大小写匹配机制(1 => 类 A、15 => 类 F 等)向前完成。

编辑:它可能很复杂或代码过载(嵌入对象),但请记住,如今,java很好地优化了这一点,它使代码保持清晰易懂。

ByteBuffer可用于解析字节流 - ByteBuffer 在 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(); 

相关内容

  • 没有找到相关文章

最新更新