ランダムな非構造化データ (圧縮/暗号化されたデータは非常によく似ています) を扱っている場合、バイトを単純に区切り文字として宣言することはできません。これは、区切り文字がそのようなデータでは常に通常のデータ バイトとして表示される可能性があるためです。
書き込みを開始するときにデータのサイズが既にわかっている場合は、通常、最初にサイズを書き、次にデータを書きます。読み返すと、最初にサイズ (たとえば、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 の後に続くことはできないため、正当なデータの組み合わせを格納するために悪用される可能性があります。