导航

03-003 StaticFiles 之 SendFileMiddleware

Posted on 2015-03-12 13:09  DotNet1010  阅读(170)  评论(0)    收藏  举报

Invoke 方法:

        public Task Invoke(HttpContext context)
        {
            // Check if there is a SendFile feature already present
            if (context.GetFeature<IHttpSendFileFeature>() == null)
            {
                context.SetFeature<IHttpSendFileFeature>(new SendFileWrapper(context.Response.Body, _logger));
            }

            return _next(context);
        }

 这里是对 IHttpSendFileFeature 赋值 接口只有一个方法:

        public interface IHttpSendFileFeature
	{
		Task SendFileAsync(string path, long offset, long? length, CancellationToken cancellation);
	}

 具体的实现代码:

           public async Task SendFileAsync(string fileName, long offset, long? length, CancellationToken cancel)
            {
                cancel.ThrowIfCancellationRequested();

                //此处有一些判断 如 是否超过文件长度

#if ASPNET50
                Stream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 1024 * 64,
                    FileOptions.Asynchronous | FileOptions.SequentialScan);
#else
                // TODO: Bring back async when the contract gets it
                Stream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 1024 * 64);
#endif
                try
                {
                    fileStream.Seek(offset, SeekOrigin.Begin);
                    if (_logger.IsEnabled(LogLevel.Verbose))
                    {
                        _logger.WriteVerbose(string.Format("Copying bytes {0}-{1} of file {2} to response body", offset, length != null ? (offset + length).ToString() : "*", fileName));
                    }
                    await StreamCopyOperation.CopyToAsync(fileStream, _output, length, cancel);
                }
                finally
                {
                    fileStream.Dispose();
                }
            }

为什么有offset 和 length? 可以获取文件的一部分 如:特别大的一个文件 可以用多线程每个线程获取文件的一部分 最后合并成完整的文件。

断点续传如:迅雷等就是利用这个来实现的。

核心的代码就这两行

  fileStream.Seek(offset, SeekOrigin.Begin);
  await StreamCopyOperation.CopyToAsync(fileStream, _output, length, cancel);
其中 _output 是 context.Response.Body。

    具体的使用例子:

await response.SendFileAsync("testFile.txt", 1, 3, CancellationToken.None);//3个字节
await response.SendFileAsync("testFile.txt");//整个文件