c# - ASP.NET MVC : is it a good idea to return a File result from a byte[]?

标签 c# asp.net-mvc

我在我的一个 Controller 中执行了一项操作,该操作创建了一个可下载的 zip 文件,该文件应提供给用户。目前我的代码看起来像这样:

using(var memoryStream = new MemoryStream()) {
    // ... use SharpZipLib to write zip file content to the above MemoryStream ...
    return File(memoryStream.ToArray(), "application/zip", "file.zip");
}

我想知道将 memoryStream 转换为 byte[] 是否是个好主意,我猜这比使用流占用更多内存? File() 有一个重载,它接受一个 Stream 对象,我传入了我的 memoryStream 变量,但随后只显示了一个空白页面。

理想情况下,我不必使用 FileStream 并将文件写入磁盘。

最佳答案

如果您真的关心内存,那么这里有一个直接写入响应流的解决方案。首先定义您的自定义 ActionResult:

public class SharpZipLibResult : FileResult
{
    private readonly string _fileDownloadName;
    private readonly string[] _filesToZip;
    private const int ChunkSize = 1024;

    public SharpZipLibResult(string fileDownloadName, params string[] filesToZip)
        : base("application/octet-stream")
    {
        _fileDownloadName = fileDownloadName;
        _filesToZip = filesToZip;
    }

    protected override void WriteFile(HttpResponseBase response)
    {
        var cd = new ContentDisposition();
        cd.FileName = _fileDownloadName;
        response.AddHeader("Content-Disposition", cd.ToString());
        response.BufferOutput = false;
        using (var zipStream = new ZipOutputStream(response.OutputStream))
        {
            foreach (var file in _filesToZip)
            {
                var entry = new ZipEntry(Path.GetFileName(file));
                zipStream.PutNextEntry(entry);
                using (var reader = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                {
                    byte[] buffer = new byte[ChunkSize];
                    int bytesRead;
                    while ((bytesRead = reader.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        byte[] actual = new byte[bytesRead];
                        Buffer.BlockCopy(buffer, 0, actual, 0, bytesRead);
                        zipStream.Write(actual, 0, actual.Length);
                    }
                }
            }
        }
    }
}

使用这种技术,您可以提供一些非常大的 zip 文件,而无需关心内存或不必清理服务器硬盘驱动器上的一些临时 zip 文件。

最后,您的 Controller 操作可能如下所示:

public ActionResult Index()
{
    return new SharpZipLibResult(
        "result.zip", 
        @"c:\work\report1.pdf",
        @"c:\work\report2.pdf",
        @"c:\work\report3.pdf"
    );
}

使用此方法可最大限度地减少内存占用,因为 zip 直接写入响应流,而响应流将由底层网络套接字表示。

当然,根据文件的存储位置,SharpZipLibResult 可以进行调整。这里我假设文件存储在文件系统上。

关于c# - ASP.NET MVC : is it a good idea to return a File result from a byte[]?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1687812/

相关文章:

c# - 使用文件

c# - 如何防止类编译?

c# - 如何使用 NHibernate 一次执行多个数据库更改?

c# - 用于打印的真实尺寸 WPF 控件

c# - 将 CDN 网址添加到 mvc 4 bundler 输出

asp.net-mvc - 我应该将每个 MVC View 命名为 Index.aspx 吗?

c# - 从 C# 中的特定 url 发送带有附件的电子邮件

asp.net-mvc - 哪里可以找到在 ASP .NET MVC2 中实现密码恢复的 C# 示例代码

c# - 多个等待操作或只有一个

c# - 如何缓存数据库表以防止在 Asp.net C# mvc 中进行许多数据库查询