从流中安全地解析字节数组的最佳分隔符

L. *_*anc 3 java encoding parsing bytearray snappy

我有一个字节流,返回一个字节数组序列,每个字节数组代表一个记录.

我想将流解析为单个byte []的列表.目前,我已经入侵了一个三字节分隔符,以便我可以识别每条记录的结尾,但是有疑虑.

我看到有一个标准的Ascii记录分隔符.

30  036 1E  00011110    RS        Record Separator
Run Code Online (Sandbox Code Playgroud)

如果字节数组(UTF-8编码)已被压缩和/或加密,使用从该字符派生的byte []是否安全?我担心的是加密/压缩输出可能会出于某种其他目的而产生记录分隔符.请注意,单个byte []记录是压缩/加密的,而不是整个流.

我正在使用Java 8并使用Snappy进行压缩.我还没有选择加密库,但它肯定是更强大,标准的私钥方法之一.

Dur*_*dal 7

如果您正在使用随机非结构化数据(压缩/加密数据非常接近),则不能简单地将字节声明为分隔符,因为分隔符始终在此类数据中显示为常规数据字节.

如果在开始写入时已知数据大小,则通常先写入大小,然后再写入数据.当你回读时,你知道你需要先读取大小(比如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);
Run Code Online (Sandbox Code Playgroud)

现在读取并读取ESCAPE字节时,读取下一个字节的x并检查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);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果要写入的字节完全随机分布,这将使流长度增加1/256,对于非完全随机的数据域,您可以选择出现频率最低的字节(通过静态数据分析或只是有根据的猜测) .

编辑:您可以通过使用更复杂的逻辑来减少转义开销,例如,示例只能创建ESCAPE + ESCAPE或ESCAPE + EOF.其他254个字节在示例中永远不会跟随ESCAPE,因此可以利用它来存储合法数据组合.


bma*_*ies 2

这是完全不安全的,你永远不知道你的数据中会出现什么。也许你应该考虑像protobuf这样的东西,或者像“首先写入记录长度,然后写入记录,然后冲洗,起泡,重复”这样的方案?

如果有长度,则不需要分隔符。您的读取端读取长度,然后知道要读取第一个记录的长度,然后知道读取下一个长度 - 所有这些都假设长度本身是固定长度的。

请参阅开发人员关于流式传输 protobuf 序列的建议