I have to download a file and I'm using this code, which is basically an AsyncTask
that is meant to update a progress bar. But, since I don't know what's the file size I've been having to use the spinner progress bar. So, how can I get the file size before start downloading it so that I can use a normal progress bar?
you can get a header called Content-Length
form the HTTP Response object that you get, this will give you the length of the file.
you should note though, that some servers don't return that information, and the only way to know the actual size is to read everything from the response.
Example:
URL url = new URL("http://server.com/file.mp3");
URLConnection urlConnection = url.openConnection();
urlConnection.connect();
int file_size = urlConnection.getContentLength();
you can usually use getContentLength , but the best thing is it get the length by yourself (since it can bypass integer's max value) .
just parse the content-length header value by yourself . better parse it as long .
example:
final URL uri=new URL(...);
URLConnection ucon;
try
{
ucon=uri.openConnection();
ucon.connect();
final String contentLengthStr=ucon.getHeaderField("content-length");
//...
}
catch(final IOException e1)
{
}
do note that i can be any string , so use try catch , and if it's -1, empty , or null , it means that you can't know the size of the file since the server doesn't allow it.
EDIT: Here's a more updated code, using Kotlin:
@JvmStatic
@WorkerThread
fun getFileSizeOfUrl(url: String): Long {
var urlConnection: URLConnection? = null
try {
val uri = URL(url)
urlConnection = uri.openConnection()
urlConnection!!.connect()
if (VERSION.SDK_INT >= Build.VERSION_CODES.N)
return urlConnection.contentLengthLong
val contentLengthStr = urlConnection.getHeaderField("content-length")
return if (contentLengthStr.isNullOrEmpty()) -1L else contentLengthStr.toLong()
} catch (ignored: Exception) {
} finally {
if (urlConnection is HttpURLConnection)
urlConnection.disconnect()
}
return -1L
}
In some environments (such as Manifest V3 browser extensions) it's impossible to access the response headers before the file is completely downloaded.
In situations like these, you might think of sending your fetch request with the 'head' method. However, the server from which you are fetching might not support it.
A good solution to overcome this challenge is to fetch 0 bytes of the file with the range header, if it's supported by the server, then use the Content-Range response header as a substitute for Content-Length.
Here's an example how to achieve this.
let response = await fetch(this.url, { headers: { 'Range': 'bytes=0-0' } });
let contentLength = parseInt(response.headers.get('Content-Range').split('/')[1], 10);
You can write a function that uses this workaround only as a fallback, as I experienced it's still slower than the fetch request with the head method.
Here's an example:
async function getFileSize(url) {
try {
// Attempt to get file size using HEAD method
let headResponse = await fetch(url, { method: 'HEAD' });
let contentLength = parseInt(headResponse.headers.get('Content-Length'), 10);
return contentLength;
} catch (headError) {
// If HEAD request fails, use Range header as fallback
try {
let rangeResponse = await fetch(url, { headers: { 'Range': 'bytes=0-0' } });
let contentRange = rangeResponse.headers.get('Content-Range');
let contentLength = parseInt(contentRange.split('/')[1], 10);
return contentLength;
} catch (rangeError) {
// Handle the error or return a default value
console.error('Failed to retrieve file size');
return null;
}
}
}
© 2022 - 2024 — McMap. All rights reserved.
urlConnection.connect()
before attempting to access theContent-Length
header. Not doing so might work, but not under all possible circumstances. – Robotize