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).

Но это кажется таким эзотерическим и запутанным, что я считаю, что должен быть более легкий путь. Либо это, либо что-то в моем подходе ошибочно.

Другие вопросы по тегам