При чтении из InputStream в ByteBuffer.array() первые 4 байта данных удаляются.

Позвольте мне дать упрощенную версию того, что я пробовал. У меня есть файловый актив, который содержит необработанный массив чисел (всего N чисел, каждое из которых имеет ширину 4 байта). Я делаю InputStream с помощью AssetManager и пытаюсь передать все данные в прямой ByteBuffer:

try (InputStream inputStream = assetsManager.open(assetFileName)) {
     int size = inputStream.available();
     assert size % 4 == 0;
     ByteBuffer bytes = ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder());
     inputStream.read(bytes.array());
}

Я думал, что это должно работать нормально, но я столкнулся с некоторым странным поведением моей программы, которое заставило меня думать, что загрузка данных в конце концов была неправильной, и действительно, после некоторой отладки первого содержимого внутри bytes и сравнения его с содержимое файла в программе просмотра HEX. Я обнаружил, что этот подход не считывает первые 4 байта, т. е. содержимое bytes начинается с моего второго числа шириной 4 байта. Признаюсь, я не проверял, что содержится в конце bytes, но будем считать, что это просто нули.

Затем я прибегнул к другому подходу, и он полностью и правильно считывает все байты (но это немного уродливо, и я бы хотел этого избежать):

 try (InputStream inputStream = assetsManager.open(assetFileName) {
      int size = inputStream.available();
      byte[] bytesArray = new byte[size];
      inputStream.read(bytesArray, 0, size);
      ByteBuffer bytes = ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder());
      bytes.put(bytesArray);
      bytes.rewind();
 }

Я действительно новичок в разработке как Java, так и Android, поэтому я спрашиваю, является ли это ошибкой на стороне платформы или есть что-то в InputStream / AssetManager.open(...), с чем мне нужно обращаться более осторожно, чтобы добиться правильного чтения данных?

Я изучил этот вопрос, который звучит похоже, но он касается С#: NetworkStream обрезает первые 4 байта при чтении

Это навело меня на мысль, что я должен также читать данные кусками и помещать их в ByteStream один за другим, но мои файлы не большие (менее 16 МБ) и при чтении явно нет гонки данных, поэтому я думаю, что inputStream.read(bytes.array()); не должен подводить странно...


person Alexey Larionov    schedule 23.06.2021    source источник
comment
ByteOrder.nativeOrder()) Какой порядок байтов может быть в буфере? Байт есть байт, я бы сказал.   -  person blackapps    schedule 23.06.2021
comment
inputStream.read(bytes.array()); Будет ли один вызов читать 16 МБ? Я думаю. int nread = inputStream.read(bytes.array()); Та же проблема с inputStream.read(bytes, 0, size);   -  person blackapps    schedule 23.06.2021
comment
16 МБ - это острый случай, обычно это около 2 МБ. Я вижу, что это может вызвать проблемы, так что это фрагментация?   -  person Alexey Larionov    schedule 23.06.2021
comment
@blackapps ByteOrder.nativeOrder() - это то, что я нашел в примере OpenGL для Android, не особо задумывался об этом, но отлично работает, когда эти двоичные данные используются для передачи на графический процессор для OpenGL.   -  person Alexey Larionov    schedule 23.06.2021
comment
byte[] bytesArray Первые четыре байта в шестнадцатеричном формате?   -  person blackapps    schedule 23.06.2021
comment
(yet it's kind of ugly and I'd like to avoid it): Нет ничего уродливого. Но вы должны проверить возвращаемое значение .read().   -  person blackapps    schedule 23.06.2021
comment
@blackapps да, 3E 79 0C 3F 49 BB 61 3E ... - это то, как начинается мой файл, 49 BB 61 3E ... - это то, что я получаю   -  person Alexey Larionov    schedule 23.06.2021
comment
@blackapps это уродливо в том смысле, что я выделяю массив байтов дважды, сначала как byte[], затем как ByteBuffer   -  person Alexey Larionov    schedule 23.06.2021
comment
Да это правда. Но зачем вам ByteBuffer, если у вас уже есть байтовый массив? Как бы вы использовали ByteBuffer для чисел, каждый из которых имеет длину четыре байта?   -  person blackapps    schedule 23.06.2021
comment
@blackapps Я передаю его необработанным функциям OpenGL, и им требуется прямое хранилище   -  person Alexey Larionov    schedule 23.06.2021
comment
49 BB 61 3E ... is what I get – ??? Не понимаю. Вы сказали, что все прошло нормально, если вы использовали этот массив.   -  person blackapps    schedule 23.06.2021
comment
Я не знаю, что вы имеете в виду под прямым хранилищем, но если им нужен ByteBuffer, тогда я могу понять, что вы делаете.   -  person blackapps    schedule 23.06.2021
comment
... извините за недоразумение, с byte[] все в порядке, но при прямом чтении в ByteBuffer я теряю первые 4 байта   -  person Alexey Larionov    schedule 23.06.2021
comment
Разве нельзя объявить небольшой массив байтов, скажем, 8192, а затем в цикле прочитать в массив и использовать bytes.put(bytesArray); несколько раз? Таким образом, у вас есть файл только один раз в памяти.   -  person blackapps    schedule 23.06.2021
comment
Я считаю, что это вполне возможно, но я был бы так же счастлив, если бы прямое чтение в ByteBuffer не теряло 4 байта, и поэтому я задал этот вопрос.   -  person Alexey Larionov    schedule 23.06.2021
comment
Цитата: Таким образом, не все реализации ByteBuffer поддерживаются массивом байтов, а когда это так, начало массива, возвращаемого .array(), может не обязательно соответствовать началу ByteBuffer. errorprone.info/bugpattern/ByteBufferBackingArray Далее я не видел примеров, когда они пытаются писать в .array() . Выглядит так, как будто вы сами это придумали.   -  person blackapps    schedule 23.06.2021
comment
Я буквально взял его из здесь, но в любом случае... Тем не менее, спасибо за ваше исследование, очень поучительно   -  person Alexey Larionov    schedule 23.06.2021