Обычно вы должны заниматься такими вещами с потоками.
Поток - это абстракция для чтения только того, что вам нужно для обработки текущего блока данных. Таким образом, вы можете прочитать правильное количество байтов в массив байтов и передать его в свою функцию синтаксического анализа.
Вы спрашиваете: «И это заставляет нас писать неэффективный код, или есть что-то, что можно сделать?»
Обычно вы получаете свои данные в виде потока, а затем, используя технику, продемонстрированную ниже, будет более результативной, потому что вы пропустите создание одной копии. (Две копии вместо трех, один раз ОС и один раз вами. Вы пропустите копию полного массива байтов, прежде чем начинать синтаксический анализ.) Если вы действительно начинаете с byte[]
, но он построен сам, тогда вы можете захотеть вместо этого нужно изменить конструкцию объекта, например { int length, int type, byte[] contentBytes }
, и передать contentBytes
в вашу функцию синтаксического анализа.
Если вам действительно нужно начинать с byte[]
, тогда техника ниже - это более удобный способ ее разобрать, это не будет более результативным.
Итак, предположим, что у вас есть буфер байтов откуда-то, и вы хотите прочитать содержимое этого буфера. Сначала вы преобразовать его в поток:
private static List<Content> read(byte[] buffer) {
try {
ByteArrayInputStream bytesStream = new ByteArrayInputStream(buffer);
return read(bytesStream);
} catch (IOException e) {
e.printStackTrace();
}
}
выше функция оборачивает массив с потоком и передает его в функцию, которая делает фактическое чтение. Если вы можете начать из потока, то, очевидно, вы можете пропустить предыдущий шаг и просто передать этот поток в следующей функции непосредственно:
private static List<Content> read(InputStream bytesStream) throws IOException {
List<Content> results = new ArrayList<Content>();
try {
// read the content...
Content content1 = readContent(bytesStream);
results.add(content1);
// I don't know if there's more than one content block but assuming
// that there is, you can just continue reading the stream...
//
// If it's a fixed number of content blocks then just read them one
// after the other... Otherwise make this a loop
Content content2 = readContent(bytesStream);
results.add(content2);
} finally {
bytesStream.close();
}
return results;
}
Поскольку ваш байт-массив содержит контент, вы хотите, чтобы прочитать содержимое блоков из поток. Поскольку у вас есть длина и тип поля, я предполагаю, что у вас есть разные блоки контента. Следующая функция считывает длину и тип и проходит обработку байт контента на соответствующую классу в зависимости от типа чтения:
private static Content readContent(InputStream stream) throws IOException {
final int CONTENT_TYPE_A = 10;
final int CONTENT_TYPE_B = 11;
// wrap the InputStream in a DataInputStream because the latter has
// convenience functions to convert bytes to integers, etc.
// Note that DataInputStream handles the stream in a BigEndian way,
// so check that your bytes are in the same byte order. If not you'll
// have to find another stream reader that can convert to ints from
// LittleEndian byte order.
DataInputStream data = new DataInputStream(stream);
int length = data.readInt();
int type = data.readInt();
// I'm assuming that above length field was the number of bytes for the
// content. So, read length number of bytes into a buffer and pass that
// to your `parseFrom(byte[])` function
byte[] contentBytes = new byte[length];
int readCount = data.read(contentBytes, 0, contentBytes.length);
if (readCount < contentBytes.length)
throw new IOException("Unexpected end of stream");
switch (type) {
case CONTENT_TYPE_A:
return ContentTypeA.parseFrom(contentBytes);
case CONTENT_TYPE_B:
return ContentTypeB.parseFrom(contentBytes);
default:
throw new UnsupportedOperationException();
}
}
я составил следующие классы содержания. Я не знаю, что protobuf
есть, но это, по-видимому преобразовать из массива байтов до фактического объекта с его parseFrom(byte[])
функции, так что принять это как псевдокод:
class Content {
// common functionality
}
class ContentTypeA extends Content {
public static ContentTypeA parseFrom(byte[] contentBytes) {
return null; // do the actual parsing of a type A content
}
}
class ContentTypeB extends Content {
public static ContentTypeB parseFrom(byte[] contentBytes) {
return null; // do the actual parsing of a type B content
}
}
использовать 'ByteBuffer'; это лучший класс для этого в JDK. Манипулировать это немного сложно (остерегайтесь позиций!). – fge
Я знаю, но даже с bytebuffer у вас нет синтаксиса (ByteBuffer, int, int), когда вы получите оставшееся от bytebuffer, вы создадите еще один байт [], чего я хочу избежать ... – vach
Извините, но Я не понимаю вашу точку зрения. Если вам действительно нужен массив, который является только частью оригинала, у вас действительно нет выбора. – fge