Я могу читать и воспроизводить звуки с помощью решения "Воспроизведение Clip
" из javasound пометить вики-страницу. Однако для звуков, которые воспроизводятся часто (например, быстрый звук лазерной пушки, шаги и т. д.), меня раздражает открытие потоков и повторное чтение файлов каждый раз, когда вы хотите создать новый Clip
. Итак, я пытаюсь кешировать прочитанные файлы в byte[]
и впоследствии загружать их из кеша.
Загрузочная часть проста:
// Get a BAIS.
ByteArrayInputStream bais = new ByteArrayInputStream(cache.get(fileName));
// Convert to an audio stream.
AudioInputStream ais = AudioSystem.getAudioInputStream(bais);
Однако первоначальное преобразование содержимого файла в массив байтов оказывается сложной задачей. Проблема в том, что я пытаюсь прочитать звуки из файла, включенного в .jar, поэтому использование java.io.File
не вариант (насколько я понимаю), и различные решения, которые я видел ( ссылки ниже) не применяются.
Мне кажется, что самой сложной частью будет получение длины файла для создания массива байтов без использования java.io.File
. Я могу прочитать байты с помощью Scanner
, но мне нужно прочитать их в какой-то массив. Должен ли я просто использовать ArrayList<Byte>
? (См. Субоптимальный пример ниже.)
Итак, мой вопрос: как лучше всего прочитать встроенный файл в byte[]
для повторного доступа позже?
Ограничения
- Я должен иметь доступ к файлам в jarfile. Я считаю, что это ограничивает меня до
Class.getResource
илиClass.getResourceAsStream
. - Байты файла должны храниться в стандартной переменной
byte[]
. - Я бы предпочел сделать это без введения ненужных зависимостей, таких как Guava или Apache Commons. Весь мой проект до сих пор находится на ванильной Java (JDK6), и я бы хотел, чтобы он оставался таким.
Что я пробовал?
Я пробовал использовать RandomAccessFile
, например:
// Get the file.
RandomAccessFile f = new RandomAccessFile(fullPath, "r");
// Create a byte array.
theseBytes = new byte[(int) f.length()];
// Read into the array.
f.read(theseBytes);
// Close the file.
f.close();
// Put in map for later reference.
byteCache.put(fullPath, theseBytes);
Однако, по-видимому, это работает только для файла, на который ссылается диск; Я получаю следующую ошибку:
java.io.FileNotFoundException: \path\to\sound\in\jar\file.wav (Система не может найти указанный путь)
Неоптимальный пример
Хотя этот пример работает, я не думаю, что ArrayList
— лучший способ сделать это из-за постоянного изменения размера и т. д.
// Get a stream.
InputStream s = clazz.getResourceAsStream(fullPath);
// Get a byte array.
ArrayList<Byte> byteArrayList = new ArrayList<Byte>();
// Create a storage variable.
int last = 0;
// Loop.
while ((last = s.read()) != -1) {
// Get it.
byteArrayList.add((byte) last);
}
// Create a byte array.
theseBytes = new byte[byteArrayList.size()];
// Loop over each element.
for (int i = 0; i < theseBytes.length; i++) {
// Set the byte.
theseBytes[i] = byteArrayList.get(i);
}