如果您正在处理随机的非结构化数据(压缩/加密数据非常相似),则不能简单地将字节声明为分隔符,因为分隔符始终可以作为此类数据中的常规数据字节出现。
如果在开始写的时候已经知道数据的大小,一般只是先写大小,再写数据。回读时,您知道您需要先读取大小(例如,int 为 4 个字节),然后再读取大小指示的字节数。
如果你在写的时候不能告诉大小,这显然是行不通的。在这种情况下,您可以使用转义机制,例如选择一个很少出现的字节作为转义字符,转义该字节在数据中的所有出现并使用不同的字节作为结束指示符。
例如
final static byte ESCAPE = (byte) 0xBC;
final static byte EOF = (byte) 0x00;
OutputStream out = ...
for (byte b : source) {
if (b == ESCAPE) {
// escape data bytes that have the value of ESCAPE
out.write(ESCAPE);
out.write(ESCAPE);
} else {
out.write(b);
}
}
// write EOF marker ESCAPE, EOF
out.write(ESCAPE);
out.write(EOF);
现在,当您读取 ESCAPE 字节时,您读取下一个字节并检查 EOF。如果它不是 EOF,则它是一个转义的 ESCAPE,它表示一个数据字节。
InputStream in = ...
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
while ((int b = in.read()) != -1) {
if (b == ESCAPE) {
b = in.read();
if (b == EOF)
break;
buffer.write(b);
} else {
buffer.write(b);
}
}
如果要写入的字节完全随机分布,这将使流长度增加 1/256,对于不完全随机的数据域,您可以选择出现频率最低的字节(通过静态数据分析或只是有根据的猜测) .
编辑:您可以通过使用更复杂的逻辑来减少转义开销,例如,示例只能创建 ESCAPE + ESCAPE 或 ESCAPE + EOF。在示例中,其他 254 个字节永远不能跟随 ESCAPE,因此可以利用它来存储合法的数据组合。