This question already has answers here:
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
(26 answers)
Closed 5 years ago.
My app send data (string or bytes) to another app copy via Bluetooth.
I try to send big text or bytes[] and get this error:
FATAL EXCEPTION: Thread-8297
java.lang.ArrayIndexOutOfBoundsException: length=1024; index=1024
at com.ramimartin.multibluetooth.bluetooth.BluetoothRunnable.run(BluetoothRunnable.java:147)
at java.lang.Thread.run(Thread.java:841)
So, why?
Code from line
BluetoothRunnable.java:147
is:
while(bytesRead == bufferSize && buffer[bufferSize] != 0) {
Full code:
int bufferSize = 1024;
int bytesRead;
byte[] buffer = new byte[bufferSize];
try {
if(this.mInputStream != null) {
bytesRead = this.mInputStream.read(buffer);
ByteBuffer bbuf = ByteBuffer.allocate(bytesRead);
if(bytesRead != -1) {
while(bytesRead == bufferSize && buffer[bufferSize] != 0) {
bbuf.put(buffer, 0, bytesRead);
if(this.mInputStream == null) {
return;
}
bytesRead = this.mInputStream.read(buffer);
}
bbuf.put(buffer, 0, bytesRead);
}
EventBus.getDefault().post(new BluetoothCommunicatorBytes(bbuf.array()));
continue;
}
} catch (IOException var8) {
Log.e(TAG, "===> Error Received Bytes IOException : " + var8.getMessage());
continue;
}
This should be:
while(bytesRead == bufferSize && buffer[bufferSize - 1] != 0)
Also there might be times when bufferSize is than 1.
And the way to read an array is:
int arr[] = new int[10];
The max index in the above case will be:
arr[9]
as index starts from 0.
Related
I am trying to establish communication between Arduino and Android over Uart. So, while reading buffer on Android side I am not getting data in chunks.
if (uartDevice != null) {
// Loop until there is no more data in the RX buffer.
try {
byte[] buffer = new byte[CHUNK_SIZE];
int read;
while ((read = uartDevice.read(buffer, buffer.length)) > 0) {
data = new String(buffer, StandardCharsets.UTF_8).substring(0, read);
System.out.println(String.format("%020x", new BigInteger(1, data.getBytes(/*YOUR_CHARSET?*/))));
} catch (IOException e) {
Log.w(TAG, "Unable to transfer data over UART", e);
}
Expected output is:
2a3619010101001a0708403031301010011214084030313010100112140845
Instead I am receiving:
2a361a010101001a070840303130101001121408403031
8403031301010011214084030313010100112140845
3031301010011214084030313010100112140845
If you want to write code that only prints the bytes that you get I would try the following:
if (uartDevice != null) {
// Loop until there is no more data in the RX buffer.
try {
byte[] buffer = new byte[CHUNK_SIZE];
int read;
while ((read = uartDevice.read(buffer, buffer.length)) > 0) {
for (int i = 0; i < read; i++) {
System.out.printf("%02x", buffer[i]);
}
}
} catch (IOException e) {
Log.w(TAG, "Unable to transfer data over UART", e);
}
System.out.println(); // Adds a newline after all bytes
}
The following is a method that takes a UartDevice as a parameter, reads from it until the end and returns a single byte array with the whole content. No arbitrary buffer that is guaranteed to hold the whole content is needed. The returned array is exactly as big as it needs to be. Only a small read buffer is used to increase performance. Error handling is ignored.
This assumes that the data is not larger than it fits into memory.
byte[] readFromDevice(UartDevice uartDevice) {
byte[] buffer = new byte[CHUNK_SIZE];
int read;
ByteArrayOutputStream data = new ByteArrayOutputStream();
while ((read = uartDevice.read(buffer, buffer.length)) > 0) {
data.write(buffer, 0, read);
}
return data.toByteArray();
}
The method returns when all data has been read and you can process the returned array at your leasure.
I set the timeout for read from SSLSocket 2 minutes. But java.net.SocketTimeoutException: Read timed do not come while the phone's screen is off. When I turn on the screen, the timeout starts working.
This is the receive method code:
public byte[] recieve() {
byte[] result = null;
try {
ByteBuffer bb = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN);
mSocket.setSoTimeout(120000);
InputStream socketOutStream = mSocket.getInputStream();
Log.d("xxx", "Waiting response's length...");
socketOutStream.read(bb.array(), 0, 4);
int length = bb.getInt();
Log.d("xxx", String.format(" Response length: %d bytes", length));
result = new byte[length];
Log.d("xxx", String.format("Waiting response..", length));
int bytesRead = socketOutStream.read(result);
if (bytesRead == length) {
Log.d("xxx", String.format(" Bytes actually read: %d", length));
return result;
}
else if (bytesRead != 0 && bytesRead < length) {
length -= bytesRead;
while (length > 0) {
int bytesActuallyRead = socketOutStream.read(result, bytesRead, length);
length -= bytesActuallyRead;
bytesRead += bytesActuallyRead;
}
return result;
}
} catch(IOException e) {
e.printStackTrace();
Log.e("xxx", String.format("Socket error: %s", e.getMessage()));
}
return null;
}
My application should work when the screen is off. As I understand, the method read is blocking. Can I make my custom timeout? How can I solve the problem?
I am trying to decide which way is better for reading a file, bytes at a time. Is one of these two ways better than the other and if so why?
1)
byte[] buffer = new byte[FILE_RETRIEVAL_BUFFER_SIZE];
int bytesRead = fileContent.read(buffer);
while (bytesRead != 1) {
fileOnDisk.write(buffer, 0, bytesRead);
bytesRead = fileContent.read(buffer);
}
2)
byte[] buffer = new byte[FILE_RETRIEVAL_BUFFER_SIZE];
while (true) {
int bytesRead = fileContent.read(buffer);
if (-1 == bytesRead)
{break;}
fileOnDisk.write(buffer, 0, bytesRead);
}
Another common idiom is this. It has neither a redundancy nor a break statement.
int bytesRead;
while ( -1 != (bytesRead = fileContent.read(buffer)) {
...
}
The first one, (just fix it and change your while(bytesRead != 1) to while(bytesRead != -1)). It states clearer when to finish the while loop.
I have a thread that is constantly reading data from an InputStream. The InputStream data is coming from a Bluetooth socket. Previously, I wasn't using the if(mmInStream.available() > 0) around the InputStream read statement and when the bluetooth socket went away (someone turned off the device), the mmInStream.read would throw a IOException and then I could process my disconnection logic. What is the best way to determine when a disconnect has occurred?
First byte of 0xEE tells me its the leader of the data packet and the second tells me the length to read.
public void run() {
byte[] tempBuffer = new byte[1024];
byte[] buffer = null;
int byteRead=0;
long timeout=0;
long wait=100;
while (true) {
try {
timeout = System.currentTimeMillis() + wait;
if(mmInStream.available() > 0) {
while((mmInStream.available() > 0) && (tempBuffer[0] != (byte) 0xEE) && (System.currentTimeMillis() < timeout)){
byteRead = mmInStream.read(tempBuffer, 0, 1);
}
if(tempBuffer[0] == (byte) 0xEE){
timeout = System.currentTimeMillis() + wait;
while(byteRead<2 && (System.currentTimeMillis() < timeout)){
byteRead += mmInStream.read(tempBuffer, 1, 1);
}
}
timeout = System.currentTimeMillis() + wait;
while((byteRead<tempBuffer[1]) && (System.currentTimeMillis() < timeout)){
byteRead += mmInStream.read(tempBuffer, byteRead, tempBuffer[1]-byteRead);
}
}
if(byteRead > 0){
//do something with the bytes read in
}
}
catch (IOException e) {
bluetoothConnectionLost();
break;
}
}
}
You don't need all this malarkey with available(). Just set a read timeout with setSoTimeout, read, detect read returning -1, use the count returned by read if > 0 rather than assuming the buffer got filled, catch SocketTimeoutException to detect read timeouts, and catch IOException to detect other breakages.
After a look at the documentation, I think it's like this:
public void run() {
byte[] tempBuffer = new byte[1024];
int byteRead = 0;
while (true) {
try {
bytesRead = mmInStream.read(tempBuffer, 0, tempBuffer.length);
if (bytesRead < 0)
// End of stream.
break;
// Do something with the bytes read in. There are bytesRead bytes in tempBuffer.
} catch (IOException e) {
bluetoothConnectionLost();
break;
}
}
}
I think it's like this:
void fun(){
isOpen = true;
try{
InputStream stream = socket.getInputStream();
while(isOpen){
byte[] buf = new byte[8];
int pos = stream.read(buf);
if (pos < 0) {
throw new IOException();
}
//dosomething...
}
}catch(IOException e) {
isOpen = false;
}finally{
//do dispose here
}
}
Server side code
public static boolean sendFile() {
int start = Integer.parseInt(startAndEnd[0]) - 1;
int end = Integer.parseInt(startAndEnd[1]) - 1;
int size = (end - start) + 1;
try {
bos = new BufferedOutputStream(initSocket.getOutputStream());
bos.write(byteArr,start,size);
bos.flush();
bos.close();
initSocket.close();
System.out.println("Send file to : " + initSocket);
} catch (IOException e) {
System.out.println(e.getLocalizedMessage());
disconnected();
return false;
}
return true;
}
Client Side
public boolean receiveFile() {
int current = 0;
try {
int bytesRead = bis.read(byteArr,0,byteArr.length);
System.out.println("Receive file from : " + client);
current = bytesRead;
do {
bytesRead =
bis.read(byteArr, current, (byteArr.length-current));
if(bytesRead >= 0) current += bytesRead;
} while(bytesRead != -1);
bis.close();
bos.write(byteArr, 0 , current);
bos.flush();
bos.close();
} catch (IOException e) {
System.out.println(e.getLocalizedMessage());
disconnected();
return false;
}
return true;
}
Client side is multithreading,server side not use multithreading. I just paste some code that made problem if you want see all code please tell me.
After I debug the code, I found that if I set max thread to any and then the first thread always stuck in this loop. That bis.read(....) always return 0. Although, server had close stream and it not get out of the loop. I don't know why ... But another threads are work correctly.
do {
bytesRead =
bis.read(byteArr, current, (byteArr.length-current));
if(bytesRead >= 0) current += bytesRead;
} while(bytesRead != -1);
How large is your input file (the one you send?) and how large is "byteArr"?
Also, by the time your check how many bytes are read, you already called bis.read(..) twice:
int bytesRead = bis.read(byteArr,0,byteArr.length);
You probably want to read/send files larger than your buffer, so you probably want to do something like this:
byte [] buffer = new byte[4096];
int bytesRead;
int totalLength = 0;
while(-1 != (bytesRead = is.read(buffer))) {
bos.write(buffer, 0, bytesRead);
totalLength += bytesRead;
}
bos.close();
is.close();
"is" would be a plain InputStream, Peter is right, you do not need to buffer it.
read() will return 0 when you give it a buffer with no room left. (Which appears to be the case here)
I would suggest you use a DataInputStream.readFully() which does this for you.
dis.readFully(byteArr); // keeps reading until the byte[] is full.
If you are only writing large byte[] or only writing one piece of data, using a Buffered Stream just adds overhead. You don't need it.
BTW: When you call close() it will call flush() for you.