Подтвердить что ты не робот

Получить имя файла при его загрузке

Мы предоставляем файлы, которые сохраняются в нашей базе данных, и единственный способ их получить: перейдите по их id, как в:

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

Все работает, поскольку я использую WebClient Class.

Есть только одна проблема, с которой я сталкиваюсь:

Как я могу получить имя файла real?

Мой код выглядит следующим образом:

WebClient client = new WebClient ();

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

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

Все, что я знаю, это идентификатор.

Этого не происходит, когда я пытаюсь получить доступ к url из браузера, где он получает правильное имя = > DownloadedFile.xls.

Каков правильный способ получить правильный ответ?

4b9b3361

Ответ 1

У меня была та же проблема, и я нашел этот класс: 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...
}

Документация по классу предполагает, что она предназначена для вложений электронной почты, но она отлично работает на сервере, который я тестировал, и очень приятно избегать синтаксического анализа.

Ответ 2

Вот полный код, требующий, чтобы сервер применял заголовок содержимого:

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

Если сервер не настроил этот заголовок, попробуйте выполнить отладку и посмотрите, что у вас есть ResponseHeaders, один из них, вероятно, будет содержать имя, которое вы хотите. Если в браузере указано имя, оно должно начинаться с где-то..:)

Ответ 3

Вам нужно посмотреть заголовок content-disposition, используя:

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

типичным примером может быть:

"attachment; filename=IDontKnowHowToGetTheRealFileNameHere.txt"

Ответ 4

Вы можете использовать HTTP content-disposition, чтобы предлагать имена файлов для содержимого, которое вы предоставляете:

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

Итак, в вашем AwesomeSite.aspx script вы должны установить заголовок content-disposition. В классе WebClient вы должны получить этот заголовок, чтобы сохранить файл, как было предложено вашим сайтом AwesomeSite.

Ответ 5

Я достигаю этого с помощью кода wst.

Вот полный код для загрузки файла url в папке c:\temp

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

Хотя решение, предложенное 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);
            }
        }
    }
}