Вы не можете просто объявить байт в качестве разделителя, если вы работаете со случайными неструктурированными данными (которые очень похожи на сжатые/зашифрованные данные), потому что разделитель всегда может отображаться как обычный байт данных в таких данных.
Если размер данных уже известен, когда вы начинаете писать, просто сначала напишите размер, а затем данные. При обратном чтении вы знаете, что вам нужно сначала прочитать размер (например, 4 байта для int), а затем столько байтов, сколько указывает размер.
Это, очевидно, не сработает, если вы не можете определить размер во время письма. В этом случае вы можете использовать механизм экранирования, например. выберите редко появляющийся байт в качестве управляющего символа, избегайте всех вхождений этого байта в данных и используйте другой байт в качестве индикатора конца.
e.g.
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 в примере, поэтому их можно использовать для хранения допустимых комбинаций данных.
person
Durandal
schedule
14.08.2015