I am downloading on my android app. I am using a local network connection and the download is really slow.
Here's he code I am using:
URL url = new URL(ep.getFileURL());
File destFile = new File(<path to sd card file>);
URLConnection uCon = url.openConnection();
InputStream is = uCon.getInputStream();
OutputStream os = new FileOutputStream(destFile);
int progress = 0;
int lastProgress = 0;
int totalSize = uCon.getContentLength();
int downloadedSize = 0;
byte[] buffer = new byte[4096];
int count = -1;
while((count = is.read(buffer)) != -1)
{
os.write(buffer, 0, count);
downloadedSize = downloadedSize + count;
progress = (int)(downloadedSize * 100.0 / totalSize);
if(progress - lastProgress >= 5) {
publishProgress(progress);
lastProgress = progress;
}
}
os.close();
Do you spot any problems? thank you.
Edit:
I tested my code using your suggestions and I got these results:
# Download times tests #
Without bufferedoutput
Downloading file: 1 ms, Start download
Downloading file: 179812 ms, Finished downloading 54687744 bytes
Downloading file: end, 179813 ms
With bufferedoutput
Downloading file: 1 ms, Start download
Downloading file: 178312 ms, Finished downloading 54687744 bytes
Downloading file: end, 178313 ms
With httpclient
Downloading file: begin
Downloading file: 1 ms, Start download
Downloading file: 178241 ms, Finished downloading 54687744 bytes
Downloading file: end, 178242 ms
So, using Buffered streams or using HttpClient directly, doesn't change anything...
I also should have mentioned that my code is inside a AsyncTask, so publishProgress() actually runs on a separated thread already...
Thank you for your help.
You should wrap your input stream with a BufferedInputStream. You're probably getting a lot more shallow reads of a few bytes and a buffered stream will alleviate some of that. I would try that first, buffering both the input and output streams to reduce the OS level write delays.
Second, I'd be careful with how you are posting progress. It looks like you are limiting the number of times it comes up, but you might want to move the download into its own runnable and use an executor service for the download and maybe start an additional thread which evaluates the progress of all downloads and fires progress messages as necessary.
Use HttpClient instead of URLConnection
Related
Update: The problem must be on the Android side, not Qt.
The problem is simply I can't send more than 1000 bytes (correctly) from Windows (via Qt) to Android. Here I post full information:
Code in Qt Creator (Windows side):
QFile inputFile(fileInfo->absoluteFilePath());
QByteArray read;
inputFile.open(QIODevice::ReadOnly);
int size = 0;
while(1){
read.clear();
read = inputFile.read(1000);
qDebug()<< "Read : " <<read.size();
size += read.size();
if(read.size() == 0){
break;
}
QByteArray toWrite(read);
newSocket->write(toWrite);
newSocket->flush();
newSocket->waitForBytesWritten();
this->sleep(1);
}
inputFile.close();
qDebug()<<"Transfer Done! " << size << " bytes";}
Java code (Android side):
DataOutputStream dos;
DataInputStream dis;
Socket s;
s = new Socket("192.168.137.1",8080);
dos = new DataOutputStream(s.getOutputStream());
dis = new DataInputStream(s.getInputStream());
while(true){
if(dis.available() > 0 ) {
int chunkSize = 1000;
byte[] b = new byte[chunkSize];
dis.read(b);
writeToExternalStoragePublic("test.png",b);}
The code works pretty good. It even works when I set the chunks size on both sides to 1,000,000, and the data is written to Android, but a lot of the bytes are empty.
Check these photos from hex Workshop data visualizer. Using 1000 as chunkSize in the left and 2000 in right.
Here are the files:
1000ChunkSize
2000ChunkSize
The problem is 1000 is too slow, and it takes a lot of time even for small files though it works. What do you suggest?
A possible problem was the timing on the server side even though it has:
waitForBytesWritten();
I put
this->sleep(1);
But it didn't help.
Update: The problem must be on the Android side, not Qt.
In my android application I am downloading large files from server(1GB) using the following:
connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setReadTimeout(7000);
connection.connect();
input = connection.getInputStream();
output = new FileOutputStream("/sdcard/Android/" + fileName, true);
byte data[] = new byte[1024];
int count;
int total = 0;
while (count = input.read(data)) > 0) {
total = total + count;
output.write(data, 0, count);
}
The code works well. But sometimes the downloaded file gets corrupted and I don't know why! Is there a mechanism or algorithm, library ... to guarantee a successful download 100%? Please help, I don't know what to do! I don't want to use checksum to check if the file is ok and if not then download it again! I want a solution to detect the problem while downloading and fix the corrupted portion instantly!
I am using the below code to download zip file in android.code works fine ,but sometimes download fails and throws socket exception. especially while Internet connection is slow(i guess).i have also posted the screen shots of logcat error message.
int count;
URL url = new URL(URL);
URLConnection conexion = url.openConnection();
conexion.connect();
int lenghtOfFile = conexion.getContentLength();
//Log.e("ANDRO_ASYNC", "Lenght of file: " + "="+lenghtOfFile);
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(StorezipFileLocation);
byte data[] = new byte[lenghtOfFile];
long total = 0;
while ((count = input.read(data)) != -1) {
total += c![enter image description here][1]ount;
publishProgress(""+(int)((total*100)/lenghtOfFile));
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
connection reset by peer usually means that you are talking to a peer wich think that the connection has already been closed. What I don't understand is why it happens when closing a FileOutputStream.
Besides, the exception does not happen in your code but in the finalizer. Is it possible that when something goes wrong, you catch the exception in an upper level and leave the connection and file opened ? The abandonned connection is closed by the finalyser, but it's too late.
I am not sure that it will solves the problem but it is a good practice to use a finally clause to be sure that files and connections are properly closed.
The log doesn't say where the crash occurs in your code. Isn't there some more info that doesn't appear in your screenshot?
It seems that it fails on the close method of your file input stream.
You could simply surround the calls to close() with a try catch block and set your stream to null (if it failed on closing)
I'a using a asynctask to download file. It works normally until i turn off wifi connection (there are no other internet connection) of my android, download dialog still and no changes. When i check by log, i discover that function read() of inputstream is non stop. So how to check this case? here is my code:
URL url = new URL(this.url);
URLConnection connection = url.openConnection();
connection.setReadTimeout(1000);
connection.connect();
// this will be useful so that you can show a typical 0-100% progress bar
int fileLength = connection.getContentLength();
fileName = "temp.zip";
// download the file
InputStream input = new BufferedInputStream(connection.getInputStream());
OutputStream output = new FileOutputStream(path+fileName);
byte buffer[] = new byte[1024000];
long total = 0;
int count;
Log.v("test download:","download in background");
while (((count = input.read(buffer)) != -1)) {
Log.v("test download:","read:"+count);
total += count;
publishProgress((int) (total * 100 / fileLength - 1));
output.write(buffer, 0, count);
}
Since you already set a timeout by calling setReadTimeout(), you should get a SocketTimeoutException shortly after the connection dropped.
Do your code happen to maybe capture this exception silently?
Your file download buffer size is too much byte buffer[] = new byte[1024]; is enough
when i try this Download a file with Android, and showing the progress in a ProgressDialog (top answer) with asynctask ,work fine, didn't get that problem
I'm downloading a video using the below code and maintaining a progress bar to show how much of the download has been completed.
ByteArrayBuffer baf = new ByteArrayBuffer((int)filesize);
long current = 0;
long notificationSize = filesize / 100 * 5;
int notifyCount = 0;
while ((current = inStream.read()) != -1)
{
baf.append((byte) current);
count += current;
//only process update once for each kb
if(count > notificationSize * notifyCount)
{
notifier.processUpdate(count);
notifyCount++;;
}
}
The issue i'm running into is the data being returned from the input stream adds up to be more than the file size. Meaning my progress bar completes before the download completes.
For example i'm download a video that has a file size of 1,849,655 bytes, but the count of the download adds to 228,932,955.
Android Progress bars use a percentage of how much of the process is complete. How do i know how much is complete if the total byte count from the download is more than the size of the file.
Worked out the issue.
When downloading and keeping track of the amount of data that has been downloaded do not use read() from the BufferedInputStream.
Instead use read(buffer, offset, length);
I also changed my code to write out the data to a file as i go instead of storing the data in memory and outputting once all data has come down.
byte[] baf = new byte[filesize];
int actual = 0;
int count = 0;
long notificationSize = filesize / 100 * 5;
int notifyCount = 0;
while (actual != -1)
{
//write data to file
fos.write(baf, 0, actual);
count += actual;
//only process update once for each kb
if(count > notificationSize * notifyCount)
{
notifier.processUpdate(count);
notifyCount++;;
}
actual = inStream.read(baf, 0, filesize);
}
I'm not really sure why read() shows it has read multiple bytes when read() is only meant to read a byte at a time.
If you really want to use read() change
count += current;
to
count++;
It's a rather inefficient way to download though as the number of loops in the while loop is much greater. After some brief performance testing seems slower to download as well (as it needs to write out to the file for each byte instead of a chunk of bytes).