Pab*_*blo 7 asp.net filestream
在我的一个asp.net Web应用程序中,我需要隐藏正在向用户提供的pdf文件的位置.
因此,我正在编写一种方法,从CMS系统上的位置检索其二进制内容,然后将字节数组刷新到Web用户.
不幸的是,我在下载流时遇到错误:"无法打开文件,因为它已被删除"(或类似于在adobe reader中打开文件时).
问题1:我做错了什么?问题2:我可以使用这种方法下载大文件吗?
private void StreamFile(IItem documentItem)
{
//CMS vendor specific API
BinaryContent itemBinaryContent = documentItem.getBinaryContent();
//Plain old .NET
Stream fileStream = itemBinaryContent.getContentStream();
var len = itemBinaryContent.getContentLength();
SendStream(fileStream, len, itemBinaryContent.getContentType());
}
private void SendStream(Stream stream, int contentLen, string contentType)
{
Response.ClearContent();
Response.ContentType = contentType;
Response.AppendHeader("content-Disposition", string.Format("inline;filename=file.pdf"));
Response.AppendHeader("content-length", contentLen.ToString());
var bytes = new byte[contentLen];
stream.Read(bytes, 0, contentLen);
stream.Close();
Response.BinaryWrite(bytes);
Response.Flush();
}
Run Code Online (Sandbox Code Playgroud)
这是我使用的方法.这会传回一个附件,因此IE会生成一个打开/保存对话框.我也碰巧知道文件不会大于1M,所以我相信有更简洁的方法可以做到这一点.
我对PDF有类似的问题,我意识到我绝对不得不使用二进制流和ReadBytes.任何有字符串的东西搞砸了.
Stream stream = GetStream(); // Assuming you have a method that does this.
BinaryReader reader = new BinaryReader(stream);
HttpResponse response = HttpContext.Current.Response;
response.ContentType = "application/pdf";
response.AddHeader("Content-Disposition", "attachment; filename=file.pdf");
response.ClearContent();
response.OutputStream.Write(reader.ReadBytes(1000000), 0, 1000000);
// End the response to prevent further work by the page processor.
response.End();
Run Code Online (Sandbox Code Playgroud)
其他答案在发送响应之前将文件内容复制到内存中.如果数据已经在内存中,那么您将拥有两个副本,这对可伸缩性来说不是很好.这可能更好地工作:
public void SendFile(Stream inputStream, long contentLength, string mimeType, string fileName)
{
string clength = contentLength.ToString(CultureInfo.InvariantCulture);
HttpResponse response = HttpContext.Current.Response;
response.ContentType = mimeType;
response.AddHeader("Content-Disposition", "attachment; filename=" + fileName);
if (contentLength != -1) response.AddHeader("Content-Length", clength);
response.ClearContent();
inputStream.CopyTo(response.OutputStream);
response.OutputStream.Flush();
response.End();
}
Run Code Online (Sandbox Code Playgroud)
由于Stream是字节的集合,因此不需要使用BinaryReader.只要输入流在文件末尾结束,您就可以在要发送到Web浏览器的流上使用CopyTo()方法.所有内容都将写入目标流,而不会制作任何数据的中间副本.
如果只需要从流中复制一定数量的字节,则可以创建一个扩展方法,以添加更多的CopyTo()重载:
public static class Extensions
{
public static void CopyTo(this Stream inStream, Stream outStream, long length)
{
CopyTo(inStream, outStream, length, 4096);
}
public static void CopyTo(this Stream inStream, Stream outStream, long length, int blockSize)
{
byte[] buffer = new byte[blockSize];
long currentPosition = 0;
while (true)
{
int read = inStream.Read(buffer, 0, blockSize);
if (read == 0) break;
long cPosition = currentPosition + read;
if (cPosition > length) read = read - Convert.ToInt32(cPosition - length);
outStream.Write(buffer, 0, read);
currentPosition += read;
if (currentPosition >= length) break;
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以像这样使用它:
inputStream.CopyTo(response.OutputStream, contentLength);
Run Code Online (Sandbox Code Playgroud)
这适用于任何输入流,但一个简单的例子是从文件系统中读取文件:
string filename = @"C:\dirs.txt";
using (FileStream fs = File.Open(filename, FileMode.Open))
{
SendFile(fs, fs.Length, "application/octet-stream", filename);
}
Run Code Online (Sandbox Code Playgroud)
如前所述,请确保您的MIME类型对于内容是正确的.
归档时间: |
|
查看次数: |
21952 次 |
最近记录: |