8

I want to read bytes from a wave file into an array. Since the number of bytes read depends upon the size of the wave file, I'm creating a byte array with a maximum size of 1000000. But this is resulting in empty values at the end of the array. So, I wanted to create a dynamically increasing array and I found that ArrayList is the solution. But the read() function of the AudioInputStream class reads bytes only into a byte array! How do I pass the values into an ArrayList instead?

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
Uday Kanth
  • 361
  • 3
  • 9
  • 16
  • What's the next steps you want to do with that byte array? Maybe you don't even need that big temporary buffer. – pcjuzer Jun 14 '11 at 08:57

3 Answers3

36

ArrayList isn't the solution, ByteArrayOutputStream is the solution. Create a ByteArrayOutputStream write your bytes to it, and then invoke toByteArray() to get the bytes.

Example of what your code should look like:

in = new BufferedInputStream(inputStream, 1024*32);
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] dataBuffer = new byte[1024 * 16];
int size = 0;
while ((size = in.read(dataBuffer)) != -1) {
    out.write(dataBuffer, 0, size);
}
byte[] bytes = out.toByteArray();
Kaj
  • 10,862
  • 2
  • 33
  • 27
  • This is by far the best and in fact the only actually correct answer that does not read bytes one by one, but for whatever reason it is showing at the bottom of the page for me... – Gerasimos R Dec 17 '18 at 14:56
17

You can have an array of byte like:

List<Byte> arrays = new ArrayList<Byte>();

To convert it back to arrays

Byte[] soundBytes = arrays.toArray(new Byte[arrays.size()]);

(Then, you will have to write a converter to transform Byte[] to byte[]).

EDIT: You are using List<Byte> wrong, I'll just show you how to read AudioInputStream simply with ByteArrayOutputStream.

AudioInputStream ais = ....;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int read;

while((read = ais.read()) != -1) {
    baos.write(read);
}

byte[] soundBytes = baos.toByteArray();

PS An IOException is thrown if frameSize is not equal to 1. Hence use a byte buffer to read data, like so:

AudioInputStream ais = ....;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int bytesRead = 0;

while((bytesRead = ais.read(buffer)) != -1) {
    baos.write(buffer, 0, bytesRead);
}

byte[] soundBytes = baos.toByteArray();
Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
  • *****.java:41: cannot find symbol symbol : method read(java.util.List) location: class javax.sound.sampled.AudioInputStream ais.read(buffer); – Uday Kanth Jun 14 '11 at 08:48
  • This doesn't compile: there's no automatic/built-in way to convert a `List` to a `byte[]`. Apart from that, using a `List` is **terribly** space-inefficient. – Joachim Sauer Jun 14 '11 at 08:53
  • @Joachim Sauer, you're right, I forgot that there needs to be a conversion from `Byte` to byte. Modifying answer. – Buhake Sindi Jun 14 '11 at 08:58
  • I guess I have a new problem now. It is saying 'Cannot read a single byte if the frame size is more than one byte' . I've used getFrameSize() of the Audioformat class and it is returning '4'. So I guess that means the current frame size is four bytes. – Uday Kanth Jun 14 '11 at 09:20
  • I didnt get this error before because I read all the bytes at once into the array. Not one by one using the while loop – Uday Kanth Jun 14 '11 at 09:22
  • @Uday Kanth, you're right, if framesize is not equal to 1, it throws an `IOException`. updating.... – Buhake Sindi Jun 14 '11 at 09:27
4

Something like this should do:

List<Byte> myBytes = new ArrayList<Byte>();

//assuming your javax.sound.sampled.AudioInputStream is called ais

while(true) {
  Byte b = ais.read();
  if (b != -1) { //read() returns -1 when the end of the stream is reached
    myBytes.add(b);
  } else {
    break;
  }
}

Sorry if the code is a bit wrong. I haven't done Java for a while.

Also, be careful if you do implement it as a while(true) loop :)

Edit: And here's an alternative way of doing it that reads more bytes each time:

int arrayLength = 1024;
List<Byte> myBytes = new ArrayList<Byte>();

while(true) {

  Byte[] aBytes = new Byte[arrayLength];
  int length = ais.read(aBytes); //length is the number of bytes read

  if (length == -1) {  //read() returns -1 when the end of the stream is reached
    break; //or return if you implement this as a method
  } else if (length == arrayLength) {  //Array is full
    myBytes.addAll(aBytes);
  } else {  //Array has been filled up to length

    for (int i = 0; i < length; i++) {
      myBytes.add(aBytes[i]);
    }
  }
}

Note that both read() methods throw an IOException - handling this is left as an exercise for the reader!

Brian Beckett
  • 4,742
  • 6
  • 33
  • 52
  • He shouldn't use a `List` of `Byte`, and reading byte by byte is very slow. – Kaj Jun 14 '11 at 08:59
  • He wants a `List` rather than an array. Also, I've provided an alternative example for reading in chunks. – Brian Beckett Jun 14 '11 at 09:03
  • he want's a `List` because he doesn't know the size up-front. This is the correct solution, even 'though it doesn't use a `List`. – Joachim Sauer Jun 14 '11 at 09:09
  • 1
    He wanted a list because he didn't know of better solutions. He wanted to have a `byte[]` in the end, and didn't care about intermediate steps. – Kaj Jun 14 '11 at 12:04