在Android中使用DownloadManager从头部获取文件名

10

我正在使用DownloadManager从URL下载视频文件。

问题是,如果我使用默认文件夹下载文件,我无法在图库中看到视频。

此外,如果我尝试使用这种方法:

request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, 'filename');

在下载之前,我需要知道文件名,但在这种情况下,我不知道。

而且,我在URL中没有文件名。

如何从报头中获取文件名并将其传递给 setDestinationInExternalPublicDir 方法? 还有其他替代方法吗?


1
问题是,如果我使用默认文件夹下载文件,我无法在图库中看到视频。你做了什么让它出现在图库中?你使用了 MediaScannerConnnectionscanFile() 吗?否则,它将不会出现在下一次周期性的文件索引中,这可能需要一段时间。"我需要在下载之前知道文件名,在这种情况下,我不知道" -- 那么发出一个 HTTP HEAD 请求或其他请求,以便您可以获取文件名。 - CommonsWare
3
对我来说不太合理的是为什么DownloadManager没有提供一个方法只设置目标文件夹并保留来自服务器的文件名。我在这里缺少一些东西吗?感谢您再次抽出时间。 - rodeleon
这将是一个不错的功能,但是 DownloadManager 并不提供它。 - CommonsWare
6
从下载响应头获取文件名?我认为这应该是“DownloadManager”的基本功能。有时在Android上工作真的很让人沮丧。 - Robert Kang
5个回答

10

如果有人需要一个执行HEAD请求以获取文件名的实现:

class GetFileName extends AsyncTask<String, Integer, String>
{
    protected String doInBackground(String... urls)
    {
        URL url;
        String filename = null;
        try {
            url = new URL(urls[0]);
            String cookie = CookieManager.getInstance().getCookie(urls[0]);
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            con.setRequestProperty("Cookie", cookie);
            con.setRequestMethod("HEAD");
            con.setInstanceFollowRedirects(false);
            con.connect();

            String content = con.getHeaderField("Content-Disposition");
            String contentSplit[] = content.split("filename=");
            filename = contentSplit[1].replace("filename=", "").replace("\"", "").trim();
        } catch (MalformedURLException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
        }
        return filename;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }
    @Override
    protected void onPostExecute(String result) {

    }
}

谢谢!所以没有办法使用DownloadManager来完成吗? :( 我正在从Google Drive下载文件,唯一提取文件名的方法是读取头文件。 - lasnow

4

小提示,在Android中有一个很好的辅助方法

URLUtil.guessFileName(url, contentDisposition, contentType);

在完成与服务器的通信后,从头文件中获取内容类型和内容分发,然后尝试从信息中查找文件名。


一个简单而有效的解决方案。谢谢。 - OMi Shah
很不幸,这个解决方案不支持来自rfc https://tools.ietf.org/html/rfc5987的filename*值。 - HotIceCream

0

我也遇到了同样的问题。我使用了@rodeleon的回答,但响应头中没有Content-Disposition。然后我分析了Chrome开发工具中的URL头,并在响应头中得到了“Location”,其中包含文件名,类似于“b/Ol/fire_mp3_24825.mp3”。所以,我使用了

String content = con.getHeaderField("Content-Disposition")

我使用了

String content = con.getHeaderField("Location") 

最后在onPostExecute中

    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        String fileName = result.substring(result.lastIndexOf("/") + 1);
        // use result as file name
        Log.d("MainActivity", "onPostExecute: " + fileName);
    }

0

方法 URLUtil.guessFileName()(在不知道Content-Disposition的情况下)以及同时被弃用的类AsyncTask,这两种方法在现在都有些问题。要正确地使用DownloadManager排队下载:

  • 首先必须在任何HTTP客户端中禁用“跟随重定向”(这是关键)。
  • 然后第一个响应将是HTTP 302(带有Location头),而不是HTTP 200
  • 获取该链接时,将获得具有Content-Disposition头部(文件名)的HTTP 200
  • 只有在已经知道文件名的情况下,才能使用DownloadManager进行排队。

这是我的一个例子:RepositoryFragment(一个GitHub客户端)。


-4
    request.setDestinationInExternalPublicDir(Environment.DIRECTORY_MOVIES, uri.getLastPathSegment());

Does not use headers. - Andrew Gaul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接