如何将内存流下载到文件?

我正在使用下面的示例代码来编写和下载内存流到C#中的文件。

MemoryStream memoryStream = new MemoryStream(); TextWriter textWriter = new StreamWriter(memoryStream); textWriter.WriteLine("Something"); byte[] bytesInStream = new byte[memoryStream.Length]; memoryStream.Write(bytesInStream, 0, bytesInStream.Length); memoryStream.Close(); Response.Clear(); Response.ContentType = "application/force-download"; Response.AddHeader("content-disposition", "attachment; filename=name_you_file.xls"); Response.BinaryWrite(bytesInStream); Response.End(); 

我收到以下错误:

指定的参数超出了有效值的范围。
参数名称:offset

可能是什么原因?

在代码中将数据复制到数组的位置,TextWriter可能没有刷新数据。 当您使用Flush()或Close()时会发生这种情况。

看看这是否有效:

 MemoryStream memoryStream = new MemoryStream(); TextWriter textWriter = new StreamWriter(memoryStream); textWriter.WriteLine("Something"); textWriter.Flush(); // added this line byte[] bytesInStream = memoryStream.ToArray(); // simpler way of converting to array memoryStream.Close(); Response.Clear(); Response.ContentType = "application/force-download"; Response.AddHeader("content-disposition", "attachment; filename=name_you_file.xls"); Response.BinaryWrite(bytesInStream); Response.End(); 

你在逻辑上做错了。 首先,您将一些文本写入MemoryStream ,然后将空数组写入同一个流。 我假设您正在尝试将流的内容复制到bytesInStream数组中。 您可以通过调用memoryStream.ToArray()来创建此数组。

或者,您可以通过使用MemoryStream.CopyTo将流直接写入响应输出流来避免arrays复制。 用这个替换你的BinaryWrite调用:

  memoryStream.Position = 0; memoryStream.CopyTo(Response.OutputStream); 

注意:由于CopyTo将从当前位置复制,因此在开始时显式定位流。

好的,因为显然只是为了提供一个工作示例而被投票,让我详细说明:

首先,你不这样做

 textWriter.Flush() 

并期望将textwriter的内容刷新到内存流。

那你不做

 memoryStream.Position = 0 

并期望内存流从位置0“写入”。

然后你做

 memoryStream.Write(bytesInStream, 0, bytesInStream.Length); 

但你的意思是

 memoryStream.Read(bytesInStream, 0, CInt(memoryStream.Length)) 

您还错过了长度为Long,而read使用了整数,因此您可以在那里获得exception。

所以这是你的代码最低限度适应“工作”(我把它复制到vb项目)

 Imports System.Web Imports System.Web.Services Public Class TextHandler Implements System.Web.IHttpHandler Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest 'context.Response.ContentType = "text/plain" 'context.Response.Write("Hello World!") Dim memoryStream As New System.IO.MemoryStream() Dim textWriter As System.IO.TextWriter = New System.IO.StreamWriter(memoryStream) textWriter.WriteLine("Something") textWriter.Flush() memoryStream.Position = 0 Dim bytesInStream As Byte() = New Byte(memoryStream.Length - 1) {} 'memoryStream.Write(bytesInStream, 0, bytesInStream.Length) memoryStream.Read(bytesInStream, 0, CInt(memoryStream.Length)) memoryStream.Close() context.Response.Clear() context.Response.ContentType = "application/force-download" context.Response.AddHeader("content-disposition", "attachment; filename=name_you_file.txt") context.Response.BinaryWrite(bytesInStream) context.Response.End() End Sub ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable Get Return False End Get End Property End Class 

然后你用

 Content-Type: application/force-download 

意思是

“我,网络服务器,我会欺骗你(浏览器)关于这个文件是什么,所以你不会把它当作PDF / Word文档/ MP3 /其他什么,并提示用户将神秘文件保存到磁盘代替”。 当客户端没有“保存到磁盘”时,这是一个肮脏的黑客攻击。

最后,你没有正确编码文件名,所以如果一个文件名使用非ASCII字符,它会乱码文件名,如果你碰巧是中文或俄文并且完全在ASCII字符集之外操作,这非常有趣。


原版的

这是我的一个ajax处理程序的快速摘录。 这是VB.NET,在转换时,要注意长度为-1的东西。

 Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest Dim strFileName As String = "Umzugsmitteilung.doc" Dim strUID As String = context.Request.QueryString("ump_uid") context.Response.Clear() 'If String.IsNullOrEmpty(strUID) Or fileData Is Nothing Then ' context.Response.Write("") ' context.Response.End() 'End If context.Response.ClearContent() 'context.Response.AddHeader("Content-Disposition", "attachment; filename=" + strFileName) context.Response.AddHeader("Content-Disposition", GetContentDisposition(strFileName)) 'context.Response.ContentType = "application/msword" context.Response.ContentType = "application/octet-stream" GetUmzugsMitteilung(strUID) context.Response.End() End Sub ' ProcessRequest Public Shared Sub SaveWordDocumentToOutputStream(strUID As String, doc As Aspose.Words.Document) Using ms As System.IO.MemoryStream = New System.IO.MemoryStream() CreateWordDocumentFromTemplate(strUID, doc, ms) ms.Position = 0 Dim bytes As Byte() = New Byte(ms.Length - 1) {} ms.Read(bytes, 0, CInt(ms.Length)) System.Web.HttpContext.Current.Response.OutputStream.Write(bytes, 0, ms.Length) ms.Close() End Using ' ms End Sub ' SaveWordDocumentToOutputStream Public Shared Function StripInvalidPathChars(str As String) As String If str Is Nothing Then Return Nothing End If Dim strReturnValue As String = "" Dim strInvalidPathChars As New String(System.IO.Path.GetInvalidPathChars()) Dim bIsValid As Boolean = True For Each cThisChar As Char In str bIsValid = True For Each cInvalid As Char In strInvalidPathChars If cThisChar = cInvalid Then bIsValid = False Exit For End If Next cInvalid If bIsValid Then strReturnValue += cThisChar End If Next cThisChar Return strReturnValue End Function ' StripInvalidPathChars Public Shared Function GetContentDisposition(ByVal strFileName As String) As String ' http://stackoverflow.com/questions/93551/how-to-encode-the-filename-parameter-of-content-disposition-header-in-http Dim contentDisposition As String strFileName = StripInvalidPathChars(strFileName) If System.Web.HttpContext.Current IsNot Nothing AndAlso System.Web.HttpContext.Current.Request.Browser IsNot Nothing Then If (System.Web.HttpContext.Current.Request.Browser.Browser = "IE" And (System.Web.HttpContext.Current.Request.Browser.Version = "7.0" Or System.Web.HttpContext.Current.Request.Browser.Version = "8.0")) Then contentDisposition = "attachment; filename=" + Uri.EscapeDataString(strFileName).Replace("'", Uri.HexEscape("'"c)) ElseIf (System.Web.HttpContext.Current.Request.Browser.Browser = "Safari") Then contentDisposition = "attachment; filename=" + strFileName Else contentDisposition = "attachment; filename*=UTF-8''" + Uri.EscapeDataString(strFileName) End If Else contentDisposition = "attachment; filename*=UTF-8''" + Uri.EscapeDataString(strFileName) End If Return contentDisposition End Function ' GetContentDisposition 

您正在使用很长的方法将字符串转换为字节。
你确定,你需要任何流吗? 为什么不使用编码?

Response.BinaryWrite(Encoding.UTF8.GetBytes("Something"))