Java: эффективное преобразование массива long в массив байтов
У меня есть массив longs
Я хочу записать на диск. Наиболее эффективные функции дискового ввода-вывода используют байтовые массивы, например:
FileOutputStream.write(byte[] b, int offset, int length)
... поэтому я хочу начать с преобразования моего long[]
в byte[]
(8 байт для каждого long
). Я изо всех сил пытаюсь найти чистый способ сделать это.
Прямое приведение типов не разрешено:
ConversionTest.java:6: inconvertible types
found : long[]
required: byte[]
byte[] byteArray = (byte[]) longArray;
^
Преобразование легко выполнить путем перебора массива, например:
ByteBuffer bytes = ByteBuffer.allocate(longArray.length * (Long.SIZE/8));
for( long l: longArray )
{
bytes.putLong( l );
}
byte[] byteArray = bytes.array();
... однако это кажется гораздо менее эффективным, чем просто обрабатывать long[] как серию байтов.
Интересно, что при чтении файла его легко "отлить" из byte[]
чтобы использовать Buffers:
LongBuffer longs = ByteBuffer.wrap(byteArray).asLongBuffer();
... но я не могу найти какую-либо функциональность, чтобы пойти в противоположном направлении.
Я понимаю, что при преобразовании из long
в byte
, но я полагаю, что я уже обращался к ним: я использую структуру Buffer, показанную выше, которая по умолчанию принимает значение с прямым порядком байтов, независимо от собственного порядка байтов.
3 ответа
Что касается эффективности, многие детали, на самом деле, вряд ли будут иметь значение. Жесткий диск, безусловно, является самой медленной частью этого процесса, и за время, которое требуется для записи одного байта на диск, вы могли бы преобразовать тысячи или даже миллионы байтов в длинные. Каждый тест производительности не скажет вам ничего о производительности реализации, но о производительности жесткого диска. В случае сомнений, следует сделать специальные тесты, сравнивающие различные стратегии преобразования и сравнивающие различные методы письма, соответственно.
Предполагая, что основной целью является функциональность, которая обеспечивает удобное преобразование и не налагает ненужных накладных расходов, я хотел бы предложить следующий подход:
Можно создать ByteBuffer
достаточного размера, рассмотрите это как LongBuffer
, используйте объем LongBuffer#put(long[])
метод (который заботится о преобразованиях порядка байтов, необходимых и делает это настолько эффективным, насколько это возможно), и, наконец, написать оригинал ByteBuffer
(который теперь заполнен long
значения) в файл, используя FileChannel
,
Следуя этой идее, я думаю, что этот метод удобен и (скорее всего) довольно эффективен:
private static void bulkAndChannel(String fileName, long longArray[])
{
ByteBuffer bytes =
ByteBuffer.allocate(longArray.length * Long.BYTES);
bytes.order(ByteOrder.nativeOrder()).asLongBuffer().put(longArray);
try (FileOutputStream fos = new FileOutputStream(fileName))
{
fos.getChannel().write(bytes);
}
catch (IOException e)
{
e.printStackTrace();
}
}
(Конечно, можно спорить о том, является ли выделение "большого" буфера наилучшей идеей. Но благодаря удобным методам Buffer
классы, это можно легко и с разумными усилиями изменить, чтобы записать "куски" данных с соответствующим размером, для случая, когда действительно нужно записать огромный массив и накладные расходы памяти при создании соответствующего ByteBuffer
будет непомерно большим)
Нет, нет банального способа конвертировать из long[]
к byte[]
,
Ваш лучший вариант, вероятно, обернет FileOutputStream
с BufferedOutputStream
а затем выписать человека byte
значения для каждого long
(используя побитовые операторы).
Другой вариант заключается в создании ByteBuffer
и положить свой long
значения в ByteBuffer
а затем написать это FileChannel
, Это обрабатывает преобразование порядка байтов для вас, но делает буферизацию более сложной.
ОП здесь.
Я подумал об одном подходе: ByteBuffer.asLongBuffer()
возвращает экземпляр ByteBufferAsLongBufferB
класс, который упаковывает ByteBuffer в интерфейс для обработки данных как long
при правильном управлении порядком байтов. Я мог бы продлить ByteBufferAsLongBufferB
и добавьте метод для возврата необработанного байтового буфера (который protected
).
Но это кажется таким эзотерическим и запутанным, что я считаю, что должен быть более легкий путь. Либо это, либо что-то в моем подходе ошибочно.