我们提供保存在我们数据库中的文件,检索它们的唯一方法是通过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
获得正确答案的正确方法是什么?
答案 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);
}
}
}
}