下载时获取文件名

时间:2010-11-04 13:04:16

标签: c# download

我们提供保存在我们数据库中的文件,检索它们的唯一方法是通过id进行检索,如下所示:

www.AwesomeURL.com/AwesomeSite.aspx?requestedFileId=23

当我使用WebClient Class时,所有内容都正常工作。

我面临的问题只有一个:

如何获取真实文件名?

我的代码看起来像这个atm:

WebClient client = new WebClient ();

string url = "www.AwesomeURL.com/AwesomeSite.aspx?requestedFileId=23";

client.DownloadFile(url, "IDontKnowHowToGetTheRealFileNameHere.txt");

我所知道的只是 id

当我尝试从浏览器访问url时,这不会发生,因为它的名称正确=>的 DownloadedFile.xls

获得正确答案的正确方法是什么?

6 个答案:

答案 0 :(得分:25)

我遇到了同样的问题,我找到了这个类: System.Net.Mime.ContentDisposition

using (WebClient client = new WebClient()){
    client.OpenRead(url);

    string header_contentDisposition = client.ResponseHeaders["content-disposition"];
    string filename = new ContentDisposition(header_contentDisposition).FileName;

    ...do stuff...
}

类文档建议它用于电子邮件附件,但它在我以前测试的服务器上工作正常,并且避免解析非常好。

答案 1 :(得分:23)

以下是所需的完整代码,假设服务器已应用content-disposition header:

using (WebClient client = new WebClient())
{
    using (Stream rawStream = client.OpenRead(url))
    {
        string fileName = string.Empty;
        string contentDisposition = client.ResponseHeaders["content-disposition"];
        if (!string.IsNullOrEmpty(contentDisposition))
        {
            string lookFor = "filename=";
            int index = contentDisposition.IndexOf(lookFor, StringComparison.CurrentCultureIgnoreCase);
            if (index >= 0)
                fileName = contentDisposition.Substring(index + lookFor.Length);
        }
        if (fileName.Length > 0)
        {
            using (StreamReader reader = new StreamReader(rawStream))
            {
                File.WriteAllText(Server.MapPath(fileName), reader.ReadToEnd());
                reader.Close();
            }
        }
        rawStream.Close();
    }
}

如果服务器没有设置此标头,请尝试调试并查看您拥有的ResponseHeader,其中一个可能包含您想要的名称。如果浏览器显示名称,则必须来自某处 ..:)

答案 2 :(得分:9)

您需要通过以下方式查看content-disposition标题:

string disposition = client.ResponseHeaders["content-disposition"];

一个典型的例子是:

"attachment; filename=IDontKnowHowToGetTheRealFileNameHere.txt"

答案 3 :(得分:3)

您可以使用HTTP content-disposition标头为您提供的内容建议文件名:

Content-Disposition: attachment; filename=downloadedfile.xls;

因此,在AwesomeSite.aspx脚本中,您需要设置content-disposition标头。在WebClient课程中,您将检索该标题,以按照AwesomeSite网站的建议保存文件。

答案 4 :(得分:2)

我用wst的代码实现了这个目标。

以下是在c:\ temp文件夹

中下载url文件的完整代码
public static void DownloadFile(string url)
    {
        using (WebClient client = new WebClient())
        {
            client.OpenRead(url);

            string header_contentDisposition = client.ResponseHeaders["content-disposition"];
            string filename = new ContentDisposition(header_contentDisposition).FileName;


            //Start the download and copy the file to the destinationFolder
            client.DownloadFile(new Uri(url), @"c:\temp\" + filename);
        }

    }

答案 5 :(得分:0)

尽管Shadow Wizard提出的解决方案对于文本文件效果很好,但我需要支持在应用程序中下载二进制文件,例如图片和可执行文件。

这里是WebClient的一个小扩展名,可以解决问题。下载是异步的。另外,文件名的默认值也是必需的,因为我们真的不知道服务器是否会发送所有正确的标头。

static class WebClientExtensions
{
    public static async Task<string> DownloadFileToDirectory(this WebClient client, string address, string directory, string defaultFileName)
    {
        if (!Directory.Exists(directory))
            throw new DirectoryNotFoundException("Downloads directory must exist");

        string filePath = null;

        using (var stream = await client.OpenReadTaskAsync(address))
        {
            var fileName = TryGetFileNameFromHeaders(client);
            if (string.IsNullOrWhiteSpace(fileName))
                fileName = defaultFileName;

            filePath = Path.Combine(directory, fileName);
            await WriteStreamToFile(stream, filePath);
        }

        return filePath;
    }

    private static string TryGetFileNameFromHeaders(WebClient client)
    {
        // content-disposition might contain the suggested file name, typically same as origiinal name on the server
        // Originally content-disposition is for email attachments, but web servers also use it.
        string contentDisposition = client.ResponseHeaders["content-disposition"];
        return string.IsNullOrWhiteSpace(contentDisposition) ?
            null :
            new ContentDisposition(contentDisposition).FileName;
    }

    private static async Task WriteStreamToFile(Stream stream, string filePath)
    {
        // Code below will throw generously, e. g. when we don't have write access, or run out of disk space
        using (var outStream = new FileStream(filePath, FileMode.CreateNew))
        {
            var buffer = new byte[8192];
            while (true)
            {
                int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
                if (bytesRead == 0)
                    break;
                // Could use async variant here as well. Probably helpful when downloading to a slow network share or tape. Not my use case.
                outStream.Write(buffer, 0, bytesRead);
            }
        }
    }
}