Java BufferedInputStream.read() IndexOutOfBounds - java

i'm want to code a method that reads part from files into byte-arrays.
for this i'm using fileinputstream and a buffered inputstream.
like this:
fis = new FileInputStream(file);
bis = new BufferedInputStream(fis);
dis = new DataInputStream(bis);
I do this only once by calling a method name "OpenFile(String File)".
Once the File has been opened with this method, i try to operate with the function: "ReadParts(byte[] buffer, int offset, int len)"
dis.read(buffer, offset, len);
for(int i = 0; i < buffer.length; i++) System.out.print((char)buffer[i]);
// used data:
// file = "C:\Temp\test.txt" with a size of 949
// buffer: always in this case with a size of 237, except for the last one its 238
// offsets: 0, 237, 474, 711
// len is always 237, except for the last one its 238
the line dis.read() throws after the first step always a indexOutOfBounds errormessage but i can't figure it out why and what. using the netbeans debugger didnt helped, since i can't find the problem with the indices.....

If you read the Stream into an array of buffers your offset and len will always have to be:
offset = 0;
len = buffer.length();
These parameters specify where the data is put in the buffer and NOT which data is read from the Stream. The Stream is read continuus (or however this gets spelled?)!
If you always call:
buffer = new byte[256];
dis.read(buffer, 0, 256);
This will happen:
Before the first call the Streamposition (position of the next byte that gets returned) is 0.
Streamposition after call=256 and buffer contains the bytes 0-255
Streamposition after call=512 and buffer contains the bytes 256-511
...
dis.reset();
Streamposition is 0 once more.
This code reads only the bytes 256-511 from a Stream into a buffer:
byte[] buffer = new byte[512];
dis.skip(256);
dis.read(buffer, 0, 256);
See that the last 256 bytes of buffer aren't filled. This is one of the differences between read(byte[], int, int) and read(byte[])!
Here are some links for you which describe the concept of a stream and the usage of read-method:
read()
Streams

how are you coming up with offset and len. My guess right now is you offset + len is greater than the buffer.

You will get IndexOutOfBoundsException - If
offset is negative,
len is negative,
len is greater than buffer.length - off
Example for point 3:
If there are 500 characters or 1500 characters in the input file, the following program will run successfully,
byte[] buffer = new byte[1000];
int offset = 0;
int len = 1000;
dis.read(buffer, offset, len);
for(int i = 0; i < buffer.length; i++) System.out.print((char)buffer[i]);
But it will fail and throw exception if,
byte[] buffer = new byte[1000];
int offset = 0;
int len = 1001;
dis.read(buffer, offset, len);
for(int i = 0; i < buffer.length; i++) System.out.print((char)buffer[i]);
Check the value of length in both the cases.

The offset is the offset in the buffer not the file.
I suspect what you want is
byte[] buffer = new byte[237];
int len = dis.read(buffer); // read another 237 bytes.
if (len < 0) throw new EOFException(); // no more data.
for(int i = 0; i < len; i++)
System.out.print((char)buffer[i]);
// or
System.out.print(new String(buffer, 0, 0, len));
In your debugger, can you check that offset >= 0 and offset + lengh <= buffer.length?
From InputStream.read()
public int read(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
One of the conditions checked for is invalid.

Related

Is there any reason to continue reading InputStream if number of read byte is 0?

Usually, when I deal with InputStream, and condition of stop reading is when the number of read byte is less than or equal to 0
For instance,
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst);
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
However, when I look at the documentation of InputStream
https://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html#read(byte[])
Only I notice that
-1 if there is no more data because the end of the stream has been reached.
I was wondering, should I refactor my code to
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst);
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) != -1) {
if (len > 0) {
out.write(buf, 0, len);
}
}
Will there be any edge case checking for while ((len = in.read(buf)) > 0) is going to cause any unwanted bug?
Since read is specified to block until data is available, the only way that it returns 0 is if the buffer you input into is is of length 0 (which would be a pretty useless buffer).
See the JavaDoc:
This method blocks until input data is available, end of file is detected, or an exception is thrown.
and
If the length of b is zero, then no bytes are read and 0 is returned; otherwise, there is an attempt to read at least one byte.
So the four possible cases are:
b is a byte[] of length 0, so 0 is returned
input data is available: non-zero bytes will be read into b and that number returned.
end of file is detected: -1 will be returned
an exception thrown: no value is returned, when a method returns abnormally with an exception.
You don't need to check if (len > 0) as out.write(buf, 0, len) handles condition when len is 0.
Save time typing the while loops in future by refactoring your code to this one liner which does the equivalent copy from in to out using a buffer and loop condition while ((len = in.read(buf)) != 0):
in.transferTo(out);

How can I solve a SonarQube complainer in for-loop?

I wrote a method copies bytes from an InputStream to an OutputStream.
// copies bytes from given input stream to specified output stream
// returns the number of bytes copied.
private static long copy(final InputStream input,
final OutputStream output)
throws IOException {
long count = 0L;
final byte[] buffer = new byte[4096];
for (int length; (length = input.read(buffer)) != -1; count += length) {
output.write(buffer, 0, length);
}
return count;
}
And SonarQube complains.
This loop's stop condition tests "length, input, buffer" but the incrementer updates "count".
It is almost always an error when a for loop's stop condition and incrementer don't act on the same variable. Even when it is not, it could confuse future maintainers of the code, and should be avoided.
Is there any better code for the same purpose?
Update
As answers recommended, I did like this and the problem's gone.
// copies bytes from given input stream to specified output stream
// returns the number of bytes copied.
private static long copy(final InputStream input,
final OutputStream output)
throws IOException {
long count = 0L;
final byte[] buffer = new byte[4096];
for (int length; (length = input.read(buffer)) != -1;) {
output.write(buffer, 0, length);
count += length;
}
return count;
}
You are abusing the for loop, that's why SonarQube raises a warning. In the following loop, you are incrementing count in the update clause but the stop condition does not depend on count
for (int length; (length = input.read(buffer)) != -1; count += length) {
^---------------------------------^ ^-------------^
does not depend on count increments count
Instead, you should use a while loop and increment the count inside the loop body:
private static long copy(final InputStream input, final OutputStream output) throws IOException {
long count = 0;
final byte[] buffer = new byte[4096];
int length;
while ((length = input.read(buffer)) != -1) {
output.write(buffer, 0, length);
count += length;
}
return count;
}
Put the count += length in the for loop body instead. It isn't an incrementer and therefor doesn't belong there, it just keeps count of the copy size.

Converting Bytes To BitSets

I am trying to figure out a way of taking data from a file and I want to store every 4 bytes as a bitset(32). I really have no idea of how to do this. I have played about with storing each byte from the file in an array and then tried to covert every 4 bytes to a bitset but I really cannot wrap my head around using bitsets. Any ideas on how to go about this?
FileInputStream data = null;
try
{
data = new FileInputStream(myFile);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int bytesRead;
while ((bytesRead = data.read(b)) != -1)
{
bos.write(b, 0, bytesRead);
}
byte[] bytes = bos.toByteArray();
Ok, you got your byte array. Now what you have to convert each byte to a bitset.
//Is number of bytes divisable by 4
bool divisableByFour = bytes.length % 4 == 0;
//Initialize BitSet array
BitSet[] bitSetArray = new BitSet[bytes.length / 4 + divisableByFour ? 0 : 1];
//Here you convert each 4 bytes to a BitSet
//You will handle the last BitSet later.
int i;
for(i = 0; i < bitSetArray.length-1; i++) {
int bi = i*4;
bitSetArray[i] = BitSet.valueOf(new byte[] { bytes[bi], bytes[bi+1], bytes[bi+2], bytes[bi+3]});
}
//Now handle the last BitSet.
//You do it here there may remain less than 4 bytes for the last BitSet.
byte[] lastBitSet = new byte[bytes.length - i*4];
for(int j = 0; j < lastBitSet.length; j++) {
lastBitSet[i] = bytes[i*4 + j]
}
//Put the last BitSet in your bitSetArray
bitSetArray[i] = BitSet.valueOf(lastBitSet);
I hope this works for you as I have written quickly and did not check if it works. But this gives you the basic idea, which was my intention at the beginning.

Decoded mp3 stream can not be read

I am developing an application that uses mp3 encoding/decoding. While in principle it behaves correctly for most of the files, there are some exceptions. I detected that these files have a missing header. I get an array out of bound exception when attempting to decode. I used two approaches but both failed.
The first:
DecodedMpegAudioInputStream dais = (DecodedMpegAudioInputStream) AudioSystem.getAudioInputStream(daisf, ais);
byte[] audioData = IOUtils.toByteArray(dais);//exception here
And the second:
ByteOutputStream bos = new ByteOutputStream();
// Get the decoded stream.
byte[] byteData = new byte[1];
int nBytesRead = 0;
int offset = 0;
int cnt=1;
while (nBytesRead != -1) {
System.out.println("cnt="+cnt);
nBytesRead = dais.read(byteData, offset, byteData.length);//exception here at first loop
if (nBytesRead != -1) {
int numShorts = nBytesRead >> 1;
for (int j = 0; j < numShorts; j++) {
bos.write(byteData[j]);
}
}
cnt+=1;
}
byte[] audioData = bos.getBytes();
It seems that there is an issue with the headers or the structure of it, because the dais stream has content/bytes. However it can be opened with audacity and ffplay so I believe there should be a workaround. Any ideas how to counter it?
You could use code redundancy to improve reliability. Look into alternative libraries, such as Xuggler or JLayer.

Java - Mixing audio files generates unwanted white noise

Recently, I've been experimenting with mixing AudioInputStreams together. After reading this post, or more importantly Jason Olson's answer, I came up with this code:
private static AudioInputStream mixAudio(ArrayList audio) throws IOException{
ArrayList<byte[]> byteArrays = new ArrayList();
long size = 0;
int pos = 0;
for(int i = 0; i < audio.size(); i++){
AudioInputStream temp = (AudioInputStream) audio.get(i);
byteArrays.add(convertStream(temp));
if(size < temp.getFrameLength()){
size = temp.getFrameLength();
pos = i;
}
}
byte[] compiledStream = new byte[byteArrays.get(pos).length];
for(int i = 0; i < compiledStream.length; i++){
int byteSum = 0;
for(int j = 0; j < byteArrays.size(); j++){
try{
byteSum += byteArrays.get(j)[i];
}catch(Exception e){
byteArrays.remove(j);
}
}
compiledStream[i] = (byte) (byteSum / byteArrays.size());
}
return new AudioInputStream(new ByteArrayInputStream(compiledStream), ((AudioInputStream)audio.get(pos)).getFormat(), ((AudioInputStream)audio.get(pos)).getFrameLength());
}
private static byte[] convertStream(AudioInputStream stream) throws IOException{
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int numRead;
while((numRead = stream.read(buffer)) != -1){
byteStream.write(buffer, 0, numRead);
}
return byteStream.toByteArray();
}
This code works very well for mixing audio files. However, it seems the more audio files being mixed, the more white noise that appears in the returned AudioInputStream. All of the files being combined are identical when it comes to formatting. If anyone has any suggestions\advice, thanks in advance.
I could be wrong, but I think your problem has to do with the fact that you are messing with the bytes instead of what the bytes mean. For instance, if you are working with a 16 bit sampling rate, 2 bytes form the number that corresponds to the amplitude rather than just 1 byte. So, you end up getting something close but not quite right.

Categories

Resources