15

我正在使用以下示例代码将内存流写入和下载到 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();

我收到以下错误:

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

可能是什么原因?

4

4 回答 4

30

在您将数据复制到数组的代码中,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();
于 2013-05-15T06:50:48.263 回答
6

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

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

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

注意:将流显式定位在开头,因为CopyTo将从当前位置复制。

于 2013-05-15T06:42:36.087 回答
3

好的,因为显然有人因为只提供一个工作示例而被否决,让我详细说明:

首先,你不做

textWriter.Flush()

并期望文本编写器的内容已被刷新到内存流。

那你不做

memoryStream.Position = 0

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

然后你做

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

但你真正的意思是

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

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

所以这是你的代码最低限度地适应“工作”(我把它复制到一个 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("<script type=""text/javascript"">alert('File does not exist !')</script>")
    '    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
于 2013-05-15T06:41:59.850 回答
0

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

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

于 2013-05-15T06:55:41.047 回答