在ASP MVC 3中创建可下载的文本文件时无法访问封闭的流

Mar*_*tin 27 c# asp.net-mvc asp.net-mvc-3

我试图提示可下载的文本文件(.txt),但我收到此错误:

无法访问封闭的Stream.

我在这里看过类似的问题: 无法访问封闭的流 但它不是很有用.

这是我的代码:

    private FileStreamResult Export()
    {
        string name = "filename.txt";

        MemoryStream stream = new MemoryStream();
        using (StreamWriter writer = new StreamWriter(stream))
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("A text...");
            writer.WriteLine(sb.ToString());
        }

        return File(stream, "text/plain", name);
    }
Run Code Online (Sandbox Code Playgroud)

更新(工作副本):

这给了我一个空白的文本文件.

private FileResult Export()
{
    string name = "filename.txt";

    MemoryStream stream = new MemoryStream();
    StreamWriter writer = new StreamWriter(stream);

    StringBuilder sb = new StringBuilder();
    sb.Append("A text...");
    writer.WriteLine(sb.ToString());

    writer.Flush();
    stream.Seek(0, SeekOrigin.Begin);

    return File(stream, "text/plain", name);
}
Run Code Online (Sandbox Code Playgroud)

Jos*_*hua 46

这是正确的,当您将流包装在另一个流中时,调用.Close().Dispose()在其中任何一个流将处理整个流.在这种情况下,包裹MemoryStream在一个StreamWriter意味着当using语句完成的StreamWriterMemoryStream均设置.

我的猜测是,因为你正在返回一个FileStreamResult封装File将在不再使用流后为你关闭流.在这种情况下,您不希望使用该using语句,并希望在返回时保持流打开.

UPDATE

由于流是前向访问,因此您需要将流返回到开头以允许读取数据.

stream.Seek(0, SeekOrigin.Begin);
Run Code Online (Sandbox Code Playgroud)

  • 由于它是一个内存流,您可能需要[Seek](http://msdn.microsoft.com/en-us/library/system.io.memorystream.seek.aspx)到流的开头.查看我的更新.你得到的是零字节,因为最后在流的当前位置没有数据.:) (2认同)

arc*_*hil 7

只需删除该using语句 - 您正在将File方法对象引用传递给方法,这就是您获得异常的原因.来自MSDN,

调用StreamWriter.Dispose时,StreamWriter对象在提供的Stream对象上调用Dispose.

我相信File在使用后会自行处理流(未通过查看源代码进行验证).

更新:

writer.Flush(); 在return语句之前应该帮助你


Jul*_*ian 6

在您的 FileStreamResult 中使用它之前,您必须将内存流的位置设置为 0,否则将从当前位置(即流的末尾)读取它。

stream.Position = 0;
return File(stream, "text/plain", name);
Run Code Online (Sandbox Code Playgroud)

刚刚有同样的事情。

我知道这个帖子很古老,只是希望能帮助其他有同样问题的人。