Массив байтов неизвестной длины в Java: Часть II - PullRequest
6 голосов
/ 26 июня 2011

Аналогично "Массив байтов неизвестной длины в Java" Мне нужно иметь возможность записать неизвестное количество байтов из источника данных в массив байтов []. Однако Мне нужна возможность чтения из байтов, которые были сохранены ранее, для алгоритма сжатия, поэтому ByteArrayOutputStream не работает для меня.

Сейчас у меня естьсхема, в которой я выделяю байтовые буферы фиксированного размера N, добавляя новый по мере того, как я достигаю N, 2N, 3N байтов и т. д. После исчерпания данных я сбрасываю все буферы в массив уже известного размера.

Есть лучший способ сделать это?Наличие буферов фиксированного размера снижает гибкость алгоритма сжатия.

Ответы [ 6 ]

5 голосов
/ 26 июня 2011

Как насчет использования кольцевого байтового буфера? Он имеет возможность динамично расти и эффективен.

Здесь есть реализация: http://ostermiller.org/utils/CircularByteBuffer.java.html

4 голосов
/ 26 июня 2011

Почему бы вам не подкласс ByteArrayOutputStream?Таким образом, ваш подкласс имеет доступ к защищенным полям buf и count, и вы можете добавить методы к своему классу для непосредственной манипуляции ими.

2 голосов
/ 02 октября 2013

Когда Крис ответил, CircularByteBuffer api - это путь. К счастью, сейчас он находится в центральном репозитории Maven. Цитируя фрагмент из этой ссылки , он выглядит так просто:

Пример однопоточного кольцевого буфера

// buffer all data in a circular buffer of infinite size
CircularByteBuffer cbb = new CircularByteBuffer(CircularByteBuffer.INFINITE_SIZE);
class1.putDataOnOutputStream(cbb.getOutputStream());
class2.processDataFromInputStream(cbb.getInputStream());

Преимущества:

  • Один класс CircularBuffer, а не два класса канала.
  • Проще преобразовать подходы "буферизировать все данные" и "дополнительные потоки".
  • Вы можете изменить размер буфера, а не полагаться на жестко заданный 1 Кб буфера в каналах.

Наконец-то у нас нет проблем с памятью и конвейерами API

2 голосов
/ 26 июня 2011

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

Таким образом, хотя вы можете создавать подклассы ByteArrayOutputStream, но даже там вы получаете накладные расходы (методы синхронизируются), которые вам не нужны.Так что я бы лично развернул свой собственный класс, который динамично растет, когда вы пишете в него.Менее эффективный, чем ваш текущий метод, но простой, и мы все знаем часть с амортизированными затратами - в противном случае вы, очевидно, также можете использовать свое решение.Пока вы оборачиваете решение в чистый интерфейс, вы скрываете сложность и все равно получаете хорошую производительность

Или иным образом сказано: нет, вы не можете сделать это более эффективно, чем уже естьи каждая встроенная коллекция Java должна работать хуже по той или иной причине.

2 голосов
/ 26 июня 2011

Расходом ByteArrayOutputStream является изменение размера базового массива.Ваша процедура фиксированного блока устраняет большую часть этого.Если изменение размера не достаточно дорого для вас (то есть при тестировании ByteArrayOutputStream является «достаточно быстрым» и не обеспечивает отмены нагрузки на память), возможно, подкласс ByteArrayOutputStream, как предлагает vanza, будет работать для вас.

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

Если алгоритм сжатия может работать в «потоке»(то есть фрагменты данных фиксированного размера), тогда размер блока должен иметь значение, поскольку вы можете скрыть все эти детали от реализации.Идеальный мир, если алгоритм сжатия хочет, чтобы его данные были порциями, соответствующими размеру блоков, которые вы выделяете, таким образом, вам не пришлось бы копировать данные для подачи в компрессор.

0 голосов
/ 26 июня 2011

Для простоты вы можете рассмотреть возможность использования java.util.ArrayList:

ArrayList<Byte> a = new ArrayList<Byte>();
a.add(value1);
a.add(value2);
...
byte value = a.get(0);

Java 1.5 и выше обеспечит автоматическую упаковку и распаковку между типами byte и Byte. Производительность может быть немного хуже, чем ByteArrayOutputStream, но ее легко читать и понимать.

...