2014-10-05 73 views
0

如果我有其编码有以下格式的字节流:解码字节

0x20 Length D_1 D_2 ... D_n CS 

0x20...marks the beginning of a data frame 
Length...number of bytes following 
D_1-D_n...data bytes (interpreted as signed ints) 
CS...One Byte Checksum 

实施例:

0x20 0x05 0x01 0x02 0xD1 0xA1 0xAF 
0x20 0x05 0x12 0x03 0x02 0x3A 0xF2 
... 
... 

我将如何从InputStream的方式解码此字节流这是常见的和有效的?我的想法是使用的BufferedInputStream和下面的过程(在伪代码):

BufferedInputStream bufIS = new BufferedInputStream(mInStream); 
while (true) { 
    byte startFrame = bufIS.read(); 

    if(startFrame == 0x20) { //first byte must mark the beginning of a data frame 
     int length = bufIS.read(); 
     byte dataframe[] = new bye[length]; 
     for (int i = 0; i<length i++) { //read data bytes 
      dateframe[i] = bufIS.read(); 
     } 

    if(verifyChecksum(bufIS.read()) postEvent(dataframe); 
    } 
} 

这是用于接收从InputStream中的数据帧以适当的方式?我无法想到更好的解决方案。另外还有一种替代read(byte[] b, int off, int len)方法,它从流中读取字节块,但不能保证读取的字节数是len,所以我认为这对我的情况没有帮助。

+0

代码将不起作用,因为长度字节实际上指定了后面的字节数,*包括*校验和。因此,无论是在你的'new byte []'还是'for'循环中,你都必须用'length - 1'替换'length'。 我仍然使用'read(byte [],int,int)'函数(重复)。实际读取的字节数由该函数返回,因此您可以判断是否需要再次调用它,或者流中是否有错误(数据提前结束)。 – misberner 2014-10-05 21:59:07

+1

BufferedInputStream默认会为您读取最多8KB的块。除非简化代码,否则我不会尝试自己读取块。 – 2014-10-05 21:59:10

回答

0

我曾经在二进制序列化的工作在某个阶段,我们确实使用BufferedInputStream read()方法。甚至在我们使用网络流结束时,'len'几乎总是不受重视。

我们所做的只不过是编写自己的帮助器方法,把参数的长度和缓冲区作为参数返回,然后返回那些需要解码的字节。只有当我们确定我们将获得流中的全部字节(以及它只是我们读取的有效流)时,我们才会使用它。

1

Id使用带有自定义反序列化的ObjectInputStream。

所以你应该编写一个具有ints列表并实现readObject的类,这样当给定一个inputstream时,它读取常量(并丢弃它),然后是长度,然后是n ints,然后是校验和,还可以选择验证它。

这将所有代码保留在一个位置,并允许您从数据流中读取完全形成的对象。