5

コントローラーActionResultを介して大きなファイルを返そうとしていますが、次のようなカスタムFileResultクラスを実装しました。

    public class StreamedFileResult : FileResult
{
    private string _FilePath;

    public StreamedFileResult(string filePath, string contentType)
        : base(contentType)
    {
        _FilePath = filePath;
    }

    protected override void WriteFile(System.Web.HttpResponseBase response)
    {
        using (FileStream fs = new FileStream(_FilePath, FileMode.Open, FileAccess.Read))
        {
            int bufferLength = 65536;
            byte[] buffer = new byte[bufferLength];
            int bytesRead = 0;

            while (true)
            {
                bytesRead = fs.Read(buffer, 0, bufferLength);

                if (bytesRead == 0)
                {
                    break;
                }

                response.OutputStream.Write(buffer, 0, bytesRead);
            }
        }
    }
}

しかし、私が抱えている問題は、ファイル全体がメモリにバッファリングされているように見えることです。これを防ぐために何をする必要がありますか?

4

2 に答える 2

8

バッファリングを防ぐために、応答をフラッシュする必要があります。ただし、content-lengthを設定せずにバッファリングを続けると、ユーザーには進行状況が表示されません。したがって、ユーザーが適切な進行状況を確認できるように、IISはコンテンツ全体をバッファリングし、コンテンツの長さを計算し、圧縮を適用してから応答を送信します。高性能でクライアントにファイルを配信するために、以下の手順を採用しています。

FileInfo path = new FileInfo(filePath);

// user will not see a progress if content-length is not specified
response.AddHeader("Content-Length", path.Length.ToString());
response.Flush();// do not add anymore headers after this...


byte[] buffer = new byte[ 4 * 1024 ]; // 4kb is a good for network chunk

using(FileStream fs = path.OpenRead()){
   int count = 0;
   while( (count = fs.Read(buffer,0,buffer.Length)) >0 ){
      if(!response.IsClientConnected) 
      {
          // network connection broke for some reason..
          break;
      }
      response.OutputStream.Write(buffer,0,count);
      response.Flush(); // this will prevent buffering...
   }
}

バッファサイズは変更できますが、下位レベルのファイルシステムも4kbのチャンクでバッファを読み取るため、4kbが理想的です。

于 2012-09-17T17:47:42.677 に答える
0

Akash Kava は、一部正しく、一部間違っています。Content-Length ヘッダーを追加したり、後でフラッシュを実行したりする必要はありません。しかし、定期的にフラッシュresponse.OutputStreamしてからresponse. ASP.NET MVC (少なくともバージョン 5) は、これを "Transfer-Encoding: chunked" 応答に自動的に変換します。

byte[] buffer = new byte[ 4 * 1024 ]; // 4kb is a good for network chunk

using(FileStream fs = path.OpenRead()){
   int count = 0;
   while( (count = fs.Read(buffer,0,buffer.Length)) >0 ){
      if(!response.IsClientConnected) 
      {
          // network connection broke for some reason..
          break;
      }
      response.OutputStream.Write(buffer,0,count);
      response.OutputStream.Flush();
      response.Flush(); // this will prevent buffering...
   }
}

私はそれをテストし、それは動作します。

于 2016-04-04T18:32:36.177 に答える