Get filename while downloading it

2019-01-21 23:06发布

We are providing files that are saved in our database and the only way to retrieve them is by going by their id as in:

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

Everything is working file as I am using the WebClient Class.

There's only one issue that I am facing:

How can I get the real filename?

My code looks like this atm:

WebClient client = new WebClient ();

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

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

All I know is the id.

This does not happen when I try accessing url from the browser where it get's the proper name => DownloadedFile.xls.

What's the proper way to get the correct response?

标签: c# download
6条回答
神经病院院长
2楼-- · 2019-01-21 23:30

I had the same problem, and I found this class: 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...
}

The class documentation suggests it's intended for email attachments, but it works fine on the server I used to test, and it's really nice to avoid the parsing.

查看更多
一夜七次
3楼-- · 2019-01-21 23:40

You need to look at the content-disposition header, via:

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

a typical example would be:

"attachment; filename=IDontKnowHowToGetTheRealFileNameHere.txt"
查看更多
放荡不羁爱自由
4楼-- · 2019-01-21 23:45

You can use HTTP content-disposition header to suggest filenames for the content you are providing:

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

So, in your AwesomeSite.aspx script, you would set the content-disposition header. In your WebClient class you would retrieve that header to save the file as suggested by your AwesomeSite site.

查看更多
5楼-- · 2019-01-21 23:50

I achieve this with the code of wst.

Here is the full code to download the url file in c:\temp folder

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);
        }

    }
查看更多
孤傲高冷的网名
6楼-- · 2019-01-21 23:53

Although the solution proposed by Shadow Wizard works well for text files, I needed to support downloading binary files, such as pictures and executables, in my application.

Here is a small extension to WebClient that does the trick. Download is asynchronous. Also default value for file name is required, because we don't really know if the server would send all the right headers.

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);
            }
        }
    }
}
查看更多
ゆ 、 Hurt°
7楼-- · 2019-01-21 23:54

Here is the full code required, assuming the server has applied 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();
    }
}

If the server did not set up this header, try debugging and see what ResponseHeaders you do have, one of them will probably contain the name you desire. If the browser show the name, it must come from somewhere.. :)

查看更多
登录 后发表回答