如何在下载文件之前知道文件的大小?

问题描述 投票:0回答:3

我必须下载一个文件,并且我正在使用此代码,它基本上是一个

AsyncTask
,用于更新进度栏。但是,由于我不知道文件大小是多少,所以我不得不使用旋转进度条。那么,如何在开始下载之前获取文件大小,以便我可以使用正常的进度条?

android download
3个回答
77
投票

您可以从您获得的 HTTP 响应对象中获取名为

Content-Length
的标头,这将为您提供文件的长度。 但您应该注意,某些服务器不会返回该信息,了解实际大小的唯一方法是从响应中读取所有内容。

示例:

URL url = new URL("http://server.com/file.mp3");
URLConnection urlConnection = url.openConnection();
urlConnection.connect();
int file_size = urlConnection.getContentLength();

19
投票

您通常可以使用 getContentLength ,但最好的是它自己获取长度(因为它可以绕过整数的最大值)。

自己解析content-length header值即可。最好解析它越长越好。

示例:

final URL uri=new URL(...);
URLConnection ucon;
try
  {
  ucon=uri.openConnection();
  ucon.connect();
  final String contentLengthStr=ucon.getHeaderField("content-length");
  //...
  }
catch(final IOException e1)
  {
  }

请注意, i 可以是任何 string ,因此请使用 try catch ,如果它是 -1、empty 或 null ,则意味着您无法知道文件的大小,因为服务器不允许。

编辑:这是使用 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
}

0
投票

在某些环境(例如 Manifest V3 浏览器扩展)中,在文件完全下载之前无法访问响应标头。

在这种情况下,您可能会考虑使用“head”方法发送获取请求。但是,您从中获取数据的服务器可能不支持它。

克服这一挑战的一个好解决方案是使用范围标头获取文件的 0 字节,如果服务器支持,则使用 Content-Range 响应标头作为 Content-Length 的替代品。

这是如何实现此目的的示例。

let response = await fetch(this.url, { headers: { 'Range': 'bytes=0-0' } });
let contentLength = parseInt(response.headers.get('Content-Range').split('/')[1], 10);

您可以编写一个仅使用此解决方法作为后备的函数,因为我发现它仍然比使用 head 方法的获取请求慢。

这是一个例子:

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;
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.