我有一个字节流,它返回一个字节数组序列,每个字节数组代表一条记录。
我想把流解析成一个单独的byte[]的列表。目前,我已经黑进了一个三字节的分隔符,这样我就可以识别每条记录的结尾,但也有顾虑。
我看到有一个标准的Ascii记录分隔符。
30 036 1E 00011110 RS  Record Separator如果字节数组(以UTF-8编码)已经被压缩和/或加密,那么使用从该字符派生的byte[]作为分隔符是否安全?我担心的是,加密/压缩输出可能会产生用于其他目的的记录分隔符。请注意,单独的byte[]记录是压缩/加密的,而不是整个流。
我正在使用Java8,并使用Snappy进行压缩。我还没有选择加密库,但它肯定是更强大的、标准的私钥方法之一。
发布于 2015-08-15 01:16:56
如果您正在处理随机的非结构化数据(压缩/加密数据与之非常相似),则不能简单地将一个字节声明为分隔符,因为分隔符始终可以作为常规数据字节出现在此类数据中。
如果在开始写入时已经知道数据的大小,通常只需先写入大小,然后再写入数据。当回读时,你知道你需要首先读取大小(例如,对于一个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);现在,当读取转义字节时,读取x个下一个字节并检查EOF。如果它不是EOF,它就是一个表示数据字节的转义。
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,对于不是完全随机的数据域,您可以选择出现频率最低的字节(通过静态数据分析或仅凭经验猜测)。
编辑:您可以通过使用更精细的逻辑来减少转义开销,例如,示例只能创建转义+转义或转义+ EOF。在示例中,其他254个字节永远不能跟在转义之后,因此可以利用它来存储合法的数据组合。
发布于 2015-08-15 00:34:28
这是完全不安全的,你永远不会知道你的数据中可能会出现什么。也许你应该考虑一些像protobuf这样的东西,或者像“先写记录长度,然后写记录,然后冲洗,起泡,重复”这样的方案?
如果你有一个长度,你不需要分隔符。您的读取端读取长度,然后知道第一条记录要读取多少,然后知道读取下一个长度--所有这些都假定长度本身是固定长度的。
参见the developers' suggestions for streaming a sequence of protobufs。
https://stackoverflow.com/questions/32014746
复制相似问题