通常你会用流来处理这种事情。
流是一种抽象,用于读取处理当前数据块所需的内容。因此,您可以将正确数量的字节读入字节数组并将其传递给您的解析函数。
你问“这是否会迫使我们编写低效的代码,或者有什么可以做的?”
通常您以流的形式获取数据,然后使用下面演示的技术会更高效,因为您跳过了制作一个副本。(两个副本而不是三个副本;一次由操作系统,一次由您。在开始解析之前,您跳过制作总字节数组的副本。)如果您实际上从 a 开始,byte[]
但它是由您自己构建的,那么您可能想要改为构造一个对象,例如{ int length, int type, byte[] contentBytes }
并传递contentBytes
给您的解析函数。
如果你真的,真的必须开始,byte[]
那么下面的技术只是一种更方便的解析方式,它不会更高效。
因此,假设您从某个地方获得了一个字节缓冲区,并且您想读取该缓冲区的内容。首先将其转换为流:
private static List<Content> read(byte[] buffer) {
try {
ByteArrayInputStream bytesStream = new ByteArrayInputStream(buffer);
return read(bytesStream);
} catch (IOException e) {
e.printStackTrace();
}
}
上面的函数用流包装字节数组并将其传递给执行实际读取的函数。如果您可以从流开始,那么显然您可以跳过上述步骤,直接将该流传递给以下函数:
private static List<Content> read(InputStream bytesStream) throws IOException {
List<Content> results = new ArrayList<Content>();
try {
// read the content...
Content content1 = readContent(bytesStream);
results.add(content1);
// I don't know if there's more than one content block but assuming
// that there is, you can just continue reading the stream...
//
// If it's a fixed number of content blocks then just read them one
// after the other... Otherwise make this a loop
Content content2 = readContent(bytesStream);
results.add(content2);
} finally {
bytesStream.close();
}
return results;
}
由于您的字节数组包含内容,您将需要从流中读取内容块。由于您有一个长度和一个类型字段,我假设您有不同类型的内容块。下一个函数读取长度和类型,并根据读取的类型将内容字节的处理传递给适当的类:
private static Content readContent(InputStream stream) throws IOException {
final int CONTENT_TYPE_A = 10;
final int CONTENT_TYPE_B = 11;
// wrap the InputStream in a DataInputStream because the latter has
// convenience functions to convert bytes to integers, etc.
// Note that DataInputStream handles the stream in a BigEndian way,
// so check that your bytes are in the same byte order. If not you'll
// have to find another stream reader that can convert to ints from
// LittleEndian byte order.
DataInputStream data = new DataInputStream(stream);
int length = data.readInt();
int type = data.readInt();
// I'm assuming that above length field was the number of bytes for the
// content. So, read length number of bytes into a buffer and pass that
// to your `parseFrom(byte[])` function
byte[] contentBytes = new byte[length];
int readCount = data.read(contentBytes, 0, contentBytes.length);
if (readCount < contentBytes.length)
throw new IOException("Unexpected end of stream");
switch (type) {
case CONTENT_TYPE_A:
return ContentTypeA.parseFrom(contentBytes);
case CONTENT_TYPE_B:
return ContentTypeB.parseFrom(contentBytes);
default:
throw new UnsupportedOperationException();
}
}
我已经组成了以下内容类。我不知道protobuf
它是什么,但它显然可以使用它的函数从字节数组转换为实际对象parseFrom(byte[])
,所以把它当作伪代码:
class Content {
// common functionality
}
class ContentTypeA extends Content {
public static ContentTypeA parseFrom(byte[] contentBytes) {
return null; // do the actual parsing of a type A content
}
}
class ContentTypeB extends Content {
public static ContentTypeB parseFrom(byte[] contentBytes) {
return null; // do the actual parsing of a type B content
}
}