26

ページの添付ファイルをユーザーに表示するための次のコードがあります。

private void GetFile(string package, string filename)
{
    var stream = new MemoryStream();

    try
    {
        using (ZipFile zip = ZipFile.Read(package))
        {
            zip[filename].Extract(stream);
        }
    }
    catch (System.Exception ex)
    {
        throw new Exception("Resources_FileNotFound", ex);
    }

    Response.ClearContent();
    Response.ClearHeaders();
    Response.ContentType = "application/unknown";

    if (filename.EndsWith(".docx"))
    {
        Response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
    }

    Response.AddHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");
    Response.BinaryWrite(stream.GetBuffer());
    stream.Dispose();
    Response.Flush();
    HttpContext.Current.ApplicationInstance.CompleteRequest();
}

問題は、サポートされているすべてのファイル (jpg、gif、png、pdf、doc など) が正常に機能することですが、.docx ファイルをダウンロードすると破損しており、開くには Office で修正する必要があります。

最初は問題が .docx を含む zip ファイルの解凍にあるのかどうかわからなかったので、出力ファイルのみを応答に入れる代わりに、最初に保存し、ファイルが正常に開かれたので、問題がわかりました。応答の書き込みにある必要があります。

何が起こっているか知っていますか?

4

9 に答える 9

32

私もこの問題に遭遇し、実際にここで答えを見つけました:

docx 形式ではResponse.End()Response.BinaryWrite.

于 2010-05-17T20:12:48.773 に答える
4

バイナリ ファイルを SQL Server に格納する場合、ファイルは最も近い単語境界までパディングされるため、余分なバイトがファイルに追加される可能性があることに注意してください。解決策は、ファイルを保存するときに元のファイル サイズを db に保存し、それを Stream オブジェクトの書き込み関数に渡す必要がある長さとして使用することです。"Stream.Write(bytes(), 0, length)". これは正しいファイル サイズを取得する唯一の信頼できる方法です。Office 2007 以降のファイルでは、ファイルの末尾に余分な文字を含めることはできません (jpg などの他のほとんどのファイル タイプは気にしません)。

于 2011-08-19T13:22:04.133 に答える
3

stream.GetBuffer()未使用のバイトを含む可能性のあるバッファ配列を返すため、使用しないでください。stream.ToArray()代わりに使用してください。また、stream.Seek(0, SeekOrigin.Begin)何かを書く前に電話をかけてみましたか?

よろしく、
オリバー・ハナッピ

于 2010-03-19T13:46:04.197 に答える
1

を使用する上記のアプローチを使用するresponse.Close()と、バイト長がヘッダーと一致しないため、IE10 などのダウンロード マネージャーは「ファイルをダウンロードできません」と言うでしょう。ドキュメントを参照してください。使用しないでくださいresponse.Close。これまで。

ただし、CompeteRequest動詞を単独で使用しても出力ストリームへのバイトの書き込みが停止されないため、WORD 2007 などの XML ベースのアプリケーションでは docx が破損していると見なされます。

この場合、ルールを破って絶対に使用しないでResponse.Endください。次のコードは、両方の問題を解決します。結果は異なる場合があります。

'*** transfer package file memory buffer to output stream
Response.ClearContent()
Response.ClearHeaders()
Response.AddHeader("content-disposition", "attachment; filename=" + NewDocFileName)
Me.Response.ContentType = "application/vnd.ms-word.document.12"
Response.ContentEncoding = System.Text.Encoding.UTF8
strDocument.Position = 0
strDocument.WriteTo(Response.OutputStream)
strDocument.Close()
Response.Flush()
'See documentation at http://blogs.msdn.com/b/aspnetue/archive/2010/05/25/response-end-response-close-and-how-customer-feedback-helps-us-improve-msdn-documentation.aspx
HttpContext.Current.ApplicationInstance.CompleteRequest() 'This is the preferred method
'Response.Close() 'BAD pattern. Do not use this approach, will cause 'cannot download file' in IE10 and other download managers that compare content-Header to actual byte count
Response.End() 'BAD Pattern as well. However, CompleteRequest does not terminate sending bytes, so Word or other XML based appns will see the file as corrupted. So use this to solve it.
于 2013-05-15T18:00:51.413 に答える
0

それはすべて大丈夫に見えます。私の唯一のアイデアは、フラッシュする前にバイトが完全に書き込まれていない場合に備えて、Response.Flushを呼び出した後、前ではなくストリームでDisposeを呼び出してみることです。

于 2010-03-19T13:40:42.317 に答える
0

.docx および .xlsx ドキュメントを開こうとすると、同じ問題が発生しました。キャッシュ可能性を NoCache ではなく ServerAndPrivate に定義することで問題を解決します

ドキュメントを呼び出す方法があります:

public void ProcessRequest(HttpContext context)

 {


       var fi = new FileInfo(context.Request.Path);
        var mediaId = ResolveMediaIdFromName(fi.Name);
        if (mediaId == null) return;

        int mediaContentId;
        if (!int.TryParse(mediaId, out mediaContentId)) return;

        var media = _repository.GetPublicationMediaById(mediaContentId);
        if (media == null) return;

        var fileNameFull = string.Format("{0}{1}", media.Name, media.Extension);
        context.Response.Clear();
        context.Response.AddHeader("content-disposition", string.Format("attachment;filename={0}", fileNameFull));            
        context.Response.Charset = "";
        context.Response.Cache.SetCacheability(HttpCacheability.ServerAndPrivate);
        context.Response.ContentType = media.ContentType;
        context.Response.BinaryWrite(media.Content);
        context.Response.Flush();          
        context.Response.End();          
    }
于 2015-01-09T13:55:52.823 に答える
0

Geoff Tanaka の回答は、binarywrite だけでなく、Response.Writefile に対しても機能します。つまり、Office ドキュメントの破損エラー「Word で読み取り不能なコンテンツが見つかりました」を取り除いた後に Response.End() を追加します。Response.ContentType に関するすべての混乱は不要であることがわかり、「application/octet-stream」に戻すことができるようになりました。もう二度と戻らない午後。

于 2021-05-18T15:34:06.050 に答える