Ответ 1
Почему вы не подклассом ByteArrayOutputStream
? Таким образом, ваш подкласс имеет доступ к защищенным полям buf
и count
, и вы можете добавлять методы в свой класс для непосредственного управления ими.
Подобно "Байт-массив неизвестной длины в java" Мне нужно уметь записывать неизвестное количество байтов из источника данных в массив byte [], Однако мне нужна возможность читать из ранее сохраненных байтов, для алгоритма сжатия, поэтому ByteArrayOutputStream не работает для меня.
Прямо сейчас у меня есть схема, где я выделяю ByteBuffers фиксированного размера N, добавляя новый, когда я добираюсь до N, 2N, 3N байтов и т.д. После того, как данные исчерпаны, я удаляю все буферы в массив уже известного размера.
Есть ли лучший способ сделать это? Наличие буферов фиксированного размера снижает гибкость алгоритма сжатия.
Почему вы не подклассом ByteArrayOutputStream
? Таким образом, ваш подкласс имеет доступ к защищенным полям buf
и count
, и вы можете добавлять методы в свой класс для непосредственного управления ими.
Как насчет использования циклического байтового буфера? Он имеет возможность динамически расти и эффективен.
Здесь реализована реализация: http://ostermiller.org/utils/CircularByteBuffer.java.html
Расход ByteArrayOutputStream - это изменение размера базового массива. Ваша фиксированная блокировка блоков устраняет большую часть этого. Если изменение размера недостаточно дорого для вас, то есть при тестировании ByteArrayOutputStream "достаточно быстро" и не обеспечивает отрицательного давления памяти), то, возможно, подклассы ByteArrayOutputStream, как было предложено vanza, будут работать на вас.
Я не знаю вашего алгоритма сжатия, поэтому не могу сказать, почему ваш список блоков делает его менее гибким, или даже почему алгоритм сжатия даже знал о блоках. Но поскольку блоки могут быть динамическими, вы можете настроить размер блока в зависимости от ситуации, чтобы лучше поддерживать разнообразие алгоритма сжатия, который вы используете.
Если алгоритм сжатия может работать с "потоком" (т.е. фиксированными размерами данных), размер блока должен иметь значение, поскольку вы могли бы скрыть все эти детали из реализации. Идеальный мир - если алгоритм сжатия хочет, чтобы его данные в кусках соответствовали размеру блоков, которые вы выделяете, таким образом вам не нужно будет копировать данные для подачи компрессора.
Хотя вы, безусловно, можете использовать ArrayList для этого, вы в значительной степени смотрите на издержки памяти 4-8 раз - при условии, что байты не были недавно выделены, но поделились одним глобальным экземпляром (поскольку это верно для целых чисел, я предполагаю, что он работает для байтов) - и вы потеряете всю локальность кэша.
Итак, пока вы можете подклассифицировать ByteArrayOutputStream, но даже там вы получаете накладные расходы (методы синхронизированы), которые вам не нужны. Поэтому я лично просто развожу свой собственный класс, который динамически растет, когда вы пишете ему. Менее эффективен, чем ваш текущий метод, но простой, и все мы знаем, что связано с амортизированными издержками - в противном случае вы, очевидно, можете использовать свое решение. Пока вы завершаете решение в чистом интерфейсе, вы скроете сложность и получите хорошую производительность.
Или иначе сказано: Нет, вы в значительной степени не можете сделать это более эффективно, чем то, что вы уже делаете, и каждая встроенная коллекция java должна работать хуже по той или иной причине.
Как Крис ответил CircularByteBuffer api - это путь. К счастью, сейчас он находится в центральной реке. Выделение фрагмента из этой ссылки, это так просто:
// 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());
Наконец, мы свободны от проблем с памятью и труб API
Для простоты вы можете использовать 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
, но ее легко читать и понимать.