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.
Related
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.
I'm trying to get a BufferedInputStream from an uploaded cvs file.
I'm working with a Multipart derived from the cvs file.
When I first get the Multipart, it's a BufferedInputStream, but the buffer is all null.
But if I look deeper down, there's another buffer in the CoyoteInputStream and that has data.
How can I get at this second buffer? My code is below.
And of course it's throwing a null exception when it gets to
while ((multiPartDataPos = stream.read(buffer)) >= 0)
What am I doing wrong? Am I mistaken that the CoyoteInputStream is the data I want?
public byte[] handleUploadedFile(Multipart multiPart) throws EOFException {
Multipart multiPartData = null;
BufferedInputStream stream = null;
int basicBufferSize = 0x2000;
byte[] buffer = new byte[basicBufferSize];
int bufferPos = 0;
try {
while (multiPart.hasNext()) {
int multiPartDataPos = bufferPos;
multiPartData = (Multipart) multiPart.next();
stream = new BufferedInputStream(multiPartData.getInputStream());
while ((multiPartDataPos = stream.read(buffer)) >= 0) {
int len = stream.read(buffer, multiPartDataPos, buffer.length - multiPartDataPos);
multiPartDataPos += len;
}
bufferPos = bufferPos + multiPartDataPos;
}
} ...
Your code doesn't make any sense.
while ((multiPartDataPos = stream.read(buffer)) >= 0) {
At this point you have read multiPartDataPos bytes into buffer, so that buffer[0..multiPartDataPos-1] contains the data just read.
int len = stream.read(buffer, multiPartDataPos, buffer.length - multiPartDataPos);
At this point you are doing another read, which could return -1, which will otherwise add some data from multiPartPos to multiPartDataPos+len-.
multiPartDataPos += len;
This step is only valid if len > 0.
And you are doing nothing with the buffer; and next time around the loop you will clobber whatever you just read.
The correct way to read any stream in Java is as follows:
while ((count = in.read(buffer)) > 0)
{
// use buffer[9..count-1], for example out.write(buffer, 0, count);
}
I don't understand why you think access to an underlying stream is required or what it's going to give you that you don't already have.
Turns out the better solution was to use move the data from an InputStream to a ByteArrayOutputStream and then return ByteArrayOutputStream.toByteArray()
Multipart multiPartData = null;
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int read;
byte[] input = new byte[4096];
InputStream is;
try {
multiPartData = (Multipart)multipart.next();
is = multiPartData.getInputStream();
while ((read = is.read(input, 0, input.length)) != -1) {
buffer.write(input, 0, read);
}
buffer.flush();
return buffer.toByteArray(); // just a test right now
}
hello well i wrote some code to download a file and put it in the desktop.
but whenever it starts downloading, it just stays at 0 bytes, why is that?
here's my code :
private void addToDesktop() throws IOException {
URL url = new URL("theurl");
URLConnection connection = url.openConnection();
InputStream inputstream = connection.getInputStream();
FileSystemView filesys = FileSystemView.getFileSystemView();
filesys.getHomeDirectory();
BufferedOutputStream bufferedoutputstream = new BufferedOutputStream(new FileOutputStream(new File(filesys.getHomeDirectory() + "/client2.jar")));
byte[] buffer = new byte[1024];
int bytesRead = 0;
while(bytesRead == inputstream.read(buffer))
{
bufferedoutputstream.write(buffer, 0 ,1000);
}
bufferedoutputstream.flush();
bufferedoutputstream.close();
inputstream.close();
}
According to the JavaDoc, the read(byte[] buffer) returns the amount of bytes read. If there are no more bytes to be read, then -1 is returned.
The problem seems to lie here: while(bytesRead == inputstream.read(buffer)). Since bytesRead will have a value of 0 however, the .read method will yield 1024. Changing it to something like so should work: while(inputstream.read(buffer) != -1)
You have:
int bytesRead = 0;
while(bytesRead == inputstream.read(buffer))
{
...
}
This is equivalent to:
while(0 == inputstream.read(buffer))
{
...
}
That condition will generally be false, and the loop will never execute. You probably meant something more like this:
int bytesRead;
while((bytesRead = inputstream.read(buffer)) > 0)
{
...
}
The moral here is: Mind your = vs. == in these types of statements.
By the way: You are writing 1000 bytes to the output file every time through the loop no matter how many bytes were read. You actually just want to be writing what was read (sometimes read() may not read the full buffer, especially at the end of the file if the buffer is larger than the remaining data). You'd want to do this instead:
while((bytesRead = inputstream.read(buffer)) > 0)
{
bufferedoutputstream.write(buffer, 0, bytesRead);
}
In java, how to read a fixed length from the inputstream and save as a file?
eg. I want to read 5M from inputStream, and save as downloadFile.txt or whatever.(BUFFERSIZE=1024)
FileOutputStream fos = new FileOutputStream(downloadFile);
byte buffer [] = new byte[BUFFERSIZE];
int temp = 0;
while ((temp = inputStream.read(buffer)) != -1)
{
fos.write(buffer, 0, temp);
}
Two options:
Just keep reading and writing until you either reach the end of the input or you've copied enough:
byte[] buffer = new byte[1024];
int bytesLeft = 5 * 1024 * 1024; // Or whatever
FileInputStream fis = new FileInputStream(input);
try {
FileOutputStream fos = new FileOutputStream(output);
try {
while (bytesLeft > 0) {
int read = fis.read(buffer, 0, Math.min(bytesLeft, buffer.length);
if (read == -1) {
throw new EOFException("Unexpected end of data");
}
fos.write(buffer, 0, read);
bytesLeft -= read;
}
} finally {
fos.close(); // Or use Guava's Closeables.closeQuietly,
// or try-with-resources in Java 7
}
} finally {
fis.close();
}
Read all 5M into memory in one call, e.g. using DataInputStream.readFully, and then write it out in one go. Simpler, but obviously uses more memory.
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.