我需要流式传输一个文件,这会导致在浏览器中另存为提示符。 问题是,文件所在的目录是虚拟映射的,因此我无法使用Server.MapPath来确定它的实际位置。该目录与网站不在同一位置(甚至是实时盒子上的物理服务器)。
我想要以下内容,但这样我就可以传递网址,而不是服务器文件路径。
我可能不得不最终从配置基本路径构建我的文件路径,然后追加到路径的其余部分,但希望我可以这样做。
var filePath = Server.MapPath(DOCUMENT_PATH);
if (!File.Exists(filePath))
return;
var fileInfo = new System.IO.FileInfo(filePath);
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", String.Format("attachment;filename=\"{0}\"", filePath));
Response.AddHeader("Content-Length", fileInfo.Length.ToString());
Response.WriteFile(filePath);
Response.End();
答案 0 :(得分:94)
您可以使用HttpWebRequest获取文件并将其流回客户端。这允许您使用URL获取文件。我发现的一个例子(但不记得在哪里给予信任)是
//Create a stream for the file
Stream stream = null;
//This controls how many bytes to read at a time and send to the client
int bytesToRead = 10000;
// Buffer to read bytes in chunk size specified above
byte[] buffer = new Byte[bytesToRead];
// The number of bytes read
try
{
//Create a WebRequest to get the file
HttpWebRequest fileReq = (HttpWebRequest) HttpWebRequest.Create(url);
//Create a response for this request
HttpWebResponse fileResp = (HttpWebResponse) fileReq.GetResponse();
if (fileReq.ContentLength > 0)
fileResp.ContentLength = fileReq.ContentLength;
//Get the Stream returned from the response
stream = fileResp.GetResponseStream();
// prepare the response to the client. resp is the client Response
var resp = HttpContext.Current.Response;
//Indicate the type of data being sent
resp.ContentType = "application/octet-stream";
//Name the file
resp.AddHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
resp.AddHeader("Content-Length", fileResp.ContentLength.ToString());
int length;
do
{
// Verify that the client is connected.
if (resp.IsClientConnected)
{
// Read data into the buffer.
length = stream.Read(buffer, 0, bytesToRead);
// and write it out to the response's output stream
resp.OutputStream.Write(buffer, 0, length);
// Flush the data
resp.Flush();
//Clear the buffer
buffer = new Byte[bytesToRead];
}
else
{
// cancel the download if client has disconnected
length = -1;
}
} while (length > 0); //Repeat until no data is read
}
finally
{
if (stream != null)
{
//Close the input stream
stream.Close();
}
}
答案 1 :(得分:15)
将url下载到字节并将字节转换为流:
using (var client = new WebClient())
{
var content = client.DownloadData(url);
using (var stream = new MemoryStream(content))
{
...
}
}
答案 2 :(得分:12)
我这样做了很多,并认为我可以添加一个更简单的答案。我在这里将它设置为一个简单的类,但我每天晚上都会运行它来收集我所关注的公司的财务数据。
class WebPage
{
public static string Get(string uri)
{
string results = "N/A";
try
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
StreamReader sr = new StreamReader(resp.GetResponseStream());
results = sr.ReadToEnd();
sr.Close();
}
catch (Exception ex)
{
results = ex.Message;
}
return results;
}
}
在这种情况下,我传入一个url,它将页面作为HTML返回。如果你想对流做一些不同的事情,你可以很容易地改变它。
你这样使用它:
string page = WebPage.Get("http://finance.yahoo.com/q?s=yhoo");
答案 3 :(得分:4)
HttpWebRequest
更改为FileWebRequest
。不确定到处都是这种情况,但我想我会添加它。另外,我删除了
var resp = Http.Current.Resonse
并且只在Http.Current.Response
被引用的地方使用了resp
。
答案 4 :(得分:3)
如果您正在寻找@Dallas答案的.NET Core版本,请使用以下内容。
Stream stream = null;
//This controls how many bytes to read at a time and send to the client
int bytesToRead = 10000;
// Buffer to read bytes in chunk size specified above
byte[] buffer = new Byte[bytesToRead];
// The number of bytes read
try
{
//Create a WebRequest to get the file
HttpWebRequest fileReq = (HttpWebRequest)HttpWebRequest.Create(@"file url");
//Create a response for this request
HttpWebResponse fileResp = (HttpWebResponse)fileReq.GetResponse();
if (fileReq.ContentLength > 0)
fileResp.ContentLength = fileReq.ContentLength;
//Get the Stream returned from the response
stream = fileResp.GetResponseStream();
// prepare the response to the client. resp is the client Response
var resp = HttpContext.Response;
//Indicate the type of data being sent
resp.ContentType = "application/octet-stream";
//Name the file
resp.Headers.Add("Content-Disposition", "attachment; filename=test.zip");
resp.Headers.Add("Content-Length", fileResp.ContentLength.ToString());
int length;
do
{
// Verify that the client is connected.
if (!HttpContext.RequestAborted.IsCancellationRequested)
{
// Read data into the buffer.
length = stream.Read(buffer, 0, bytesToRead);
// and write it out to the response's output stream
resp.Body.Write(buffer, 0, length);
//Clear the buffer
buffer = new Byte[bytesToRead];
}
else
{
// cancel the download if client has disconnected
length = -1;
}
} while (length > 0); //Repeat until no data is read
}
finally
{
if (stream != null)
{
//Close the input stream
stream.Close();
}
}
答案 5 :(得分:0)
如果我们在Citrix Netscaler上使用Load Balancer(无WAF策略),则达拉斯已接受的解决方案正在为我们工作。
当文件与WAF关联时,文件下载无法通过Netscaler的LB进行,因为当前情况(内容长度不正确)违反了RFC,并且AppFW重置了连接,但没有如果未关联WAF政策,则会发生这种情况。
所以缺少的是:
Response.End();
另请参阅: Trying to stream a PDF file with asp.net is producing a "damaged file"
答案 6 :(得分:-2)
您可以尝试将DirectoryEntry类与IIS路径前缀一起使用:
using(DirectoryEntry de = new DirectoryEntry("IIS://Localhost/w3svc/1/root" + DOCUMENT_PATH))
{
filePath = de.Properties["Path"].Value;
}
if (!File.Exists(filePath))
return;
var fileInfo = new System.IO.FileInfo(filePath);
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", String.Format("attachment;filename=\"{0}\"", filePath));
Response.AddHeader("Content-Length", fileInfo.Length.ToString());
Response.WriteFile(filePath);
Response.End();