I am trying to download a file (mp3) from my server.
I want to show the downloading progress, but I am facing a problem that whole time the file size is -1.
The screenshot:
My code:
try {
URL url = new URL(urls[0]);
// URLConnection connection = url.openConnection();
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(true);
connection.connect();
int fileSize = connection.getContentLength();
if (fileSize == -1)
fileSize = connection.getHeaderFieldInt("Length", -1);
InputStream is = new BufferedInputStream(url.openStream());
OutputStream os = new FileOutputStream(myFile);
byte data[] = new byte[1024];
long total = 0;
int count;
while ((count = is.read(data)) != -1) {
total += count;
Log.d("fileSize", "Lenght of file: " + fileSize);
Log.d("total", "Lenght of file: " + total);
// publishProgress((int) (total * 100 / fileSize));
publishProgress("" + (int) ((total * 100) / fileSize));
os.write(data, 0, count);
}
os.flush();
os.close();
is.close();
} catch (Exception e) {
e.printStackTrace();
}
I get the garbage value for the fileSize which return -1 (int fileSize = connection.getContentLength();)
Inspect the headers the server is sending. Very probably the server is sending Transfer-Encoding: Chunked and no Content-Length header at all. This is a common practice in HTTP/1.1. If the server isn't sending the length, the client obviously can't know it. If this is the case, and you have no control over the server code, the best thing to do is probably display a spinner type of indicator only.
Related
In my Android application, I am using WIFI link speed to get the speed of the WIFI
and get the length content of a file before downloading the file
and then I am trying to get the esitmated time of download before downloading the file
but the time I get is incorrect I don't know why !
that is my code to estimate the time before downloading
URL u = new URL(url);
HttpURLConnection c = (HttpURLConnection) u.openConnection();
c.setRequestMethod("GET");
c.connect();
contentLength = Long.parseLong(c.getHeaderField("Content-Length"));
System.out.println("content"+contentLength);
float contentLength_float=contentLength/(float)(1000*1000);//migabyte
float speed=((float)(mActivity.speed_wifi()))/(float)8;//convert mbps(migabit) to migabyte ps
float sec=contentLength_float/speed;//get the sec from m/m/s
and function wifi speed ()
public int speed_wifi()
{
WifiManager mainWifi;
mainWifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = mainWifi.getConnectionInfo();
int speed=0;
if(wifiInfo.getBSSID()!=null)
{
speed=wifiInfo.getLinkSpeed();
}
return speed;
}
The wifi link speed you get by using that function is the maximum speed that can be achieved by the wifi in the phone, it is not the actual speed.
There is no way of determining the wifi speed before the download starts.
What you can do is that, start showing the estimated time as the download is started based on the current download speed. For this -
find out how much data is downloaded in a small chunk of time like 2 sec which will be current_speed = data_downloaded/time (time can be 2 sec or anything you want)
Now the estimated time will be file_size/current_speed.
So in this way you can start showing the estimated time just 1 or 2 seconds after the download is started.
use AysnTask
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
try {
URL url = new URL(sUrl[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
// expect HTTP 200 OK, so we don't mistakenly save error report
// instead of the file
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
return "Server returned HTTP " + connection.getResponseCode()
+ " " + connection.getResponseMessage();
}
// this will be useful to display download percentage
// might be -1: server did not report the length
int fileLength = connection.getContentLength();
// download the file
input = connection.getInputStream();
output = new FileOutputStream("/sdcard/file_name.extension");
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
// allow canceling with back button
if (isCancelled()) {
input.close();
return null;
}
total += count;
// publishing the progress....
if (fileLength > 0) // only if total length is known
publishProgress((int) (total * 100 / fileLength));
output.write(data, 0, count);
}
} catch (Exception e) {
return e.toString();
} finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
} catch (IOException ignored) {
}
if (connection != null)
connection.disconnect();
}
i want to download a file through InputStream from some offSet,
i know that i can do this by read method of InputStream but it requires a parameter byteCount
but i don't know how to calculate byteCount for read Method
My Code is
try {
URL url;
url = new URL(uri);
HttpURLConnection c = (HttpURLConnection) url
.openConnection();
c.setConnectTimeout(1000000);
c.connect();
int lenghtOfFile = c.getContentLength();
Log.i("fileSize", lenghtOfFile + "");
File file = new File(
Environment.getExternalStorageDirectory() + "/"
+ Environment.DIRECTORY_DOWNLOADS);
file.mkdirs();
File outputFile = new File(file, "4k1.jpg");
FileOutputStream fos = new FileOutputStream(outputFile);
Log.v("Place", "trying...");
InputStream is = c.getInputStream();
Log.v("errorPart", c.getURL().toString());
if (c.getURL().toString().contains("404"))
Log.v("Error", "404 Error");
Log.v("Place", "1st attempt success");
byte[] buffer = new byte[1024];
int len1 = 0;
Log.v("Place", "Download started!");
int on = 0;
while ((len1 = is.read(buffer)) != -1) {
fos.write(buffer, 0, len1);
Log.v("is", "running " + len1);
}
Log.v("Place", "Download Finished!");
fos.close();
is.close();
} catch (Exception e) {
e.printStackTrace();
}
Please try to explain your answer, i am newbiee
You need to tell it how many bytes it can read. This is to prevent the read() method copy data over memory that it shouldn't. You should therefore pass the size of the buffer. In the code above this will be 1024. You may want to use private static int BUFFER_SIZE = 1024 and use this constant in both the new and read() so that if you change the size of the buffer you don't forget to change the parameter to the read() function as well.
private static final int BUFFER_SIZE = 1024;
...
byte[] buffer = new byte[BUFFER_SIZE];
int len1 = 0;
Log.v("Place", "Download started!");
int on = 0;
while ((len1 = is.read(buffer,0,BUFFER_SIZE)) != -1) {
fos.write(buffer, 0, len1);
Log.v("is", "running " + len1);
}
...
Why not directly use the class, CountingInputStream, provided by Apache. This class has been perfectly designed to match your requirment.
There is no direct access to the file size from HttpURLConnection You can use the nio cache under your file stream In a one-time generated file.
You don't really need to provide byteCount for read method. Using is.read(buffer)) will simply read out 1024 bytes (since defined by the length of your buffer array) at every round till -1 is returned.
I am trying to upload a file to a server with following code, the upload works, but the payload is added to the file, you can see it for example uploading a text file:
private Integer doFileUpload(final String urlServer) {
HttpURLConnection connection = null;
DataOutputStream outputStream = null;
FileInputStream fileInputStream = null;
final String pathToOurFile = mFileInfo.getProviderPath();
final String lineEnd = "\r\n";
final String twoHyphens = "--";
final String boundary = "*****";
int fileLength;
int bytesToRead, bufferSize;
final long fileSize;
byte[] buffer;
final int maxBufferSize = 1 * 1024 * 1024;
try {
final File file = new File(pathToOurFile);
fileInputStream = new FileInputStream(file);
final URL url = new URL(urlServer);
connection = (HttpURLConnection) url.openConnection();
final String[] payload = { twoHyphens + boundary + lineEnd,
"Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + pathToOurFile + "\"" + lineEnd, lineEnd, lineEnd,
twoHyphens + boundary + twoHyphens + lineEnd };
int payloadLength = 0;
for (final String string : payload) {
payloadLength += string.getBytes("UTF-8").length;
}
Logger.d(AsyncEgnyteUploadFile.LOGGING_TAG, "payload length: " + payloadLength);
fileLength = (int) file.length();
Logger.d(AsyncEgnyteUploadFile.LOGGING_TAG, "bytes: " + fileLength);
connection.setFixedLengthStreamingMode(fileLength + payloadLength);
fileSize = fileLength;
// Allow Inputs & Outputs
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
connection.setReadTimeout(5000);
connection.setConnectTimeout(5000);
connection.setRequestProperty("Authorization", "Bearer " + mToken);
// Enable POST method
connection.setRequestMethod(HttpPost.METHOD_NAME);
connection.setRequestProperty("Connection", "close");
// This header doesn't count to the number of bytes being sent.
connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
connection.connect();
outputStream = new DataOutputStream(connection.getOutputStream());
outputStream.writeBytes(payload[0]);
outputStream.writeBytes(payload[1]);
outputStream.writeBytes(payload[2]);
bufferSize = Math.min(fileLength, maxBufferSize);
buffer = new byte[bufferSize];
long totalBytesRead = 0;
long lastProgressTime = 0;
// Read file
bytesToRead = fileInputStream.read(buffer, 0, bufferSize);
boolean stopUploading = (FileState.UPLOADING != mFileInfo.getState() || isCancelled());
while (bytesToRead > 0 && !stopUploading)
{
outputStream.write(buffer);
totalBytesRead += bytesToRead;
Logger.d(AsyncEgnyteUploadFile.LOGGING_TAG, "bytes written: " + totalBytesRead);
final long now = System.currentTimeMillis();
bufferSize = (int) Math.min(fileLength - totalBytesRead, maxBufferSize);
buffer = new byte[bufferSize];
bytesToRead = fileInputStream.read(buffer, 0, bufferSize);
}
outputStream.writeBytes(payload[3]);
outputStream.writeBytes(payload[4]);
// Responses from the server (code and message)
final int serverResponseCode = connection.getResponseCode();
if (serverResponseCode == HttpStatus.SC_OK || serverResponseCode == HttpStatus.SC_CREATED) {
mAlreadyUploaded = true;
return JBError.JBERR_SUCCESS;
} else {
Log.e(AsyncEgnyteUploadFile.LOGGING_TAG, "error code: " + serverResponseCode);
return serverResponseCode;
}
} catch (final SocketTimeoutException e) {
..
} catch (final UnknownHostException e) {
..
} catch (final SocketException e) {
..
} catch (final IOException e) {
..
} catch (final Exception ex) {
..
} finally {
closeAll(connection, fileInputStream, outputStream);
}
}
Uploading a text file with only 12345 inside with this code results in following:
--*****
Content-Disposition: form-data; name="uploadedfile";filename="/storage/emulated/0/Download/3.txt"
12345
--*****--
What am I doing wrong?
You copy code is wrong. This is how to copy between streams in Java:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
Notes:
You must check all reads for end of stream.
You must use the read count in the write() method.
You don't need a new buffer per read, and you don't need a buffer the size of the file. This will work with any buffer size greater than zero. I usually use 8192.
I suspect that your server is not designed / configured to handle "multi-part" uploads.
It certainly looks like it is treating this as a plain upload ... and I cannot see anything wring with the multi-part encapsulation.
(EJP is correct, but that is not what is causing your problem here. Your example shows that all of the characters were sent ...)
I have a sample code to download some data (pdf,gif and mp3) from a web and its a swing application.It works perfectly in Windows 7 but not working in Windows xp.
My code is
public static Float downloadFile(String targetUrl,File filePath)
{
try
{
Integer count=0;
URL url = new URL(targetUrl);
HttpURLConnection connection=(HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(true);
connection.setConnectTimeout(10000);
connection.connect();
int lenghtOfFile = connection.getContentLength();
Thread.sleep(100);
InputStream input = new BufferedInputStream(url.openStream());
Thread.sleep(100);
OutputStream output = new FileOutputStream(filePath);
byte data[] = new byte[input.available()];
long total = 0;
while ((count = input.read(data)) != -1)
{
total += count;
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
}
catch (Exception e)
{
e.printStackTrace();
}
return 2.5f;
}
}
It enters into the infinite while loop by setting the code to 0
Q: What is "input.available()" when you initialize your buffer? If it happens to be "0" at that moment, you'd be sad.
One solution is to use a fixed-length buffer (e.g. 8192).
URL url;
url = new URL("http://download.thinkbroadband.com/5MB.zip");
File fileThatExists = new File("/sdcard/testfile");
URLConnection conexion = url.openConnection();
conexion.setRequestProperty("Range", "bytes=" + fileThatExists.length() + "-");
// Resume download.
conexion.setRequestProperty("If-Range", "Mon, 02 Jun 2008 15:30:42 GMT");
conexion.connect();
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream("/sdcard/testfile", true);
byte data[] = new byte[1024];
long total = 0;
int i = 0;
while ((count = input.read(data)) != -1) {
total += count;
i++;
output.write(data, 0, count);
}
}
I tried to resume download. But If my file is 5200kb, and I resume download after 100kb, I got file 5300kb. What's wrong with this code?