读取二进制文件并使用Response.BinaryWrite()

时间:2009-05-11 15:35:11

标签: c# asp.net

我有一个应用需要从文件系统中读取PDF文件,然后将其写出给用户。 PDF是183KB,似乎完美无缺。当我使用底部的代码时,浏览器获取一个224KB的文件,我从Acrobat Reader收到一条消息,说文件已损坏且无法修复。

这是我的代码(我也尝试过使用File.ReadAllBytes(),但我得到同样的东西):

using (FileStream fs = File.OpenRead(path))
{
    int length = (int)fs.Length;
    byte[] buffer;

    using (BinaryReader br = new BinaryReader(fs))
    {
        buffer = br.ReadBytes(length);
    }

    Response.Clear();
    Response.Buffer = true;
    Response.AddHeader("content-disposition", String.Format("attachment;filename={0}", Path.GetFileName(path)));
    Response.ContentType = "application/" + Path.GetExtension(path).Substring(1);
    Response.BinaryWrite(buffer);
}

10 个答案:

答案 0 :(得分:23)

尝试添加

到Response.End();

调用Response.BinaryWrite()。

之后

您可能无意中在Response.BinaryWrite之后发回其他内容,这可能会混淆浏览器。 Response.End将确保浏览器仅获得您真正想要的内容。

答案 1 :(得分:16)

        Response.BinaryWrite(bytes);
        Response.Flush();
        Response.Close();
        Response.End();

这对我们有用。我们从SQL Reporting Services创建PDF。

答案 2 :(得分:7)

我们已经使用了很多成功。 WriteFile为您下载,并在最后将Flush / End发送给客户端。

            //Use these headers to display a saves as / download
            //Response.ContentType = "application/octet-stream";
            //Response.AddHeader("Content-Disposition", String.Format("attachment; filename={0}.pdf", Path.GetFileName(Path)));

            Response.ContentType = "application/pdf";
            Response.AddHeader("Content-Disposition", String.Format("inline; filename={0}.pdf", Path.GetFileName(Path)));

            Response.WriteFile(path);
            Response.Flush();
            Response.End();

答案 3 :(得分:5)

由于您是直接从文件系统发送文件而没有中间处理,为什么不使用Response.TransmitFile呢?

Response.Clear();
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition",
    "attachment; filename=\"" + Path.GetFileName(path) + "\"");
Response.TransmitFile(path);
Response.End();

(我怀疑您的问题是由于缺少Response.End造成的,这意味着您将页面的其余内容发送到PDF数据中。)

答案 4 :(得分:4)

仅供将来参考,如本博文中所述: http://blogs.msdn.com/b/aspnetue/archive/2010/05/25/response-end-response-close-and-how-customer-feedback-helps-us-improve-msdn-documentation.aspx

建议致电Response.Close()Response.End() - 而是使用CompleteRequest()

您的代码看起来有点像这样:

    byte[] bytes = {};

    bytes = GetBytesFromDB();  // I use a similar way to get pdf data from my DB

    Response.Clear();
    Response.ClearHeaders();
    Response.Buffer = true;
    Response.Cache.SetCacheability(HttpCacheability.NoCache);
    Response.ContentType = "application/pdf";
    Response.AppendHeader("Content-Disposition", "attachment; filename=" + anhangTitel);
    Response.AppendHeader("Content-Length", bytes.Length.ToString());
    this.Context.ApplicationInstance.CompleteRequest();

答案 5 :(得分:2)

请在使用Response.TransmitFile:http://improve.dk/blog/2008/03/29/response-transmitfile-close-will-kill-your-application

之前阅读此内容

答案 6 :(得分:1)

也许你错过了关闭de Binary Stream的Response.close

答案 7 :(得分:1)

在我的MVC应用程序中,我为所有响应启用了gzip压缩。如果您正在使用gzip响应从ajax调用中读取此二进制写入,则需要使用gzip压缩的bytearray而不是需要使用的原始bytearray。

//c# controller is compressing the result after the response.binarywrite

[compress]
public ActionResult Print(int id)       
{
... 
var byteArray=someService.BuildPdf(id);
return  return this.PDF(byteArray, "test.pdf");
}

//where PDF is a custom actionresult that eventually does this:
 public class PDFResult : ActionResult
{
...
    public override void ExecuteResult(ControllerContext context)
    {
        //Set the HTTP header to excel for download
        HttpContext.Current.Response.Clear();
        //HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";
        HttpContext.Current.Response.ContentType = "application/pdf";
        HttpContext.Current.Response.AddHeader("content-disposition", string.Concat("attachment; filename=", fileName));
        HttpContext.Current.Response.AddHeader("Content-Length", pdfBytes.Length.ToString());
        //Write the pdf file as a byte array to the page
        HttpContext.Current.Response.BinaryWrite(byteArray);
        HttpContext.Current.Response.End();
    }
}

//javascript

function pdf(mySearchObject) {
    return $http({
    method: 'Post',
    url: '/api/print/',
    data: mySearchObject,
    responseType: 'arraybuffer',
    headers: {
    'Accept': 'application/pdf',
    }
    }).then(function (response) {

var type = response.headers('Content-Type');
//if response.data is gzipped, this blob will be incorrect.  you have to uncompress it first.
var blob = new Blob([response.data], { type: type });
var fileName = response.headers('content-disposition').split('=').pop();

if (window.navigator.msSaveOrOpenBlob) { // for IE and Edge
    window.navigator.msSaveBlob(blob, fileName);
} else {

    var anchor = angular.element('<a/>');
    anchor.css({ display: 'none' }); // Make sure it's not visible
    angular.element(document.body).append(anchor); // Attach to document

    anchor.attr({
    href: URL.createObjectURL(blob),
    target: '_blank',
    download: fileName
    })[0].click();

    anchor.remove();
}
});

}

“var blob = new Blob([response.data],{type:type});” 这将为您提供在将该字节数组转换为javascript中的文件时尝试打开的无效/损坏文件(如果您不首先解压缩它)。

要解决此问题,您可以选择阻止对此二进制数据进行gzipping,以便您可以将其正确地转换为正在下载的文件,或者在将其转换为javascript代码之前必须将其解压缩。一个文件。

答案 8 :(得分:0)

除了Igor的Response.Close()之外,我还要添加一个Response.Flush()。

答案 9 :(得分:0)

我还发现有必要添加以下内容:

Response.Encoding = Encoding.Default

如果我没有包含这个内容,我的JPEG就会损坏并且会以字节大小加倍。

但仅当处理程序从ASPX页面返回时。它似乎从ASHX运行,这不是必需的。