VB.NEt 无法 stream/download 压缩文件到客户端

VB.NEt cannot stream/download zip file to client

我有一个 PDF 字符串列表,其中包含“http://whatever.pdf”形式的字符串,需要创建它们的 zip 文件并将其作为下载流式传输到客户端。

奇怪的是,如果我创建了 zip(我正在使用 ZipOutputStream)并将文件写入磁盘,它就可以正常工作,我能够打开生成的 zip 文件并毫无问题地解压缩它,但是如果我流式传输(我需要做的)我得到一个相同大小的 zip 文件,但在尝试打开它时出错。

创建压缩包:

Private Function CreateZip(pdfPathList As List(Of String), fileRoot As String) As String

    Response.Clear()
    Response.BufferOutput = False
    Response.ContentType = "application/zip"
    Response.AddHeader("content-disposition", "attachment; filename=pdf.zip")

    Dim pdfPathListLocal As List(Of String) = Utility.DownloadFilesFromList(pdfPathList, fileRoot)
    Dim outputMemStream = Utility.GenerateZipOutpuStream(pdfPathListLocal)
    Dim zipName As String = Guid.NewGuid.ToString() & ".zip"
    outputMemStream.Position = 0
    'Utility.WriteMemoryStreamToDisk(outputMemStream, fileRoot & "\" & zipName) => This line creates a valid zip file on disk, but I need to avoid it.

    Response.AddHeader("Content-Length", outputMemStream.Length)
    Response.Write(outputMemStream) => Writes the file ok in downloads, but apparently corrupted.

    Return zipName

End Function

从列表下载文件:

Public Shared Function DownloadFilesFromList(pdfPathList As List(Of String), fileRoot As String) As List(Of String)

    Dim pdfPathListLocal As New List(Of String)

    Dim Client As WebClient = New WebClient()
    For Each strFile In pdfPathList
        Dim sFile As String = Path.GetFileName(strFile)
        Dim localFile As String = fileRoot + "\" + sFile
        Client.DownloadFile(strFile, localFile)
        pdfPathListLocal.Add(localFile)
    Next

    Return pdfPathListLocal

End Function

生成 ZipOutpuStream:

Public Shared Function GenerateZipOutpuStream(pdfPathListLocal As List(Of String)) As MemoryStream

    Dim outputMemStream = New MemoryStream()
    Dim strmZipOutputStream = New ZipOutputStream(outputMemStream)
    strmZipOutputStream.SetLevel(9)

    Dim objCrc32 As New Crc32()

    For Each strFile In pdfPathListLocal
        Dim strmFile As FileStream = IO.File.OpenRead(strFile)
        Dim abyBuffer(Convert.ToInt32(strmFile.Length - 1)) As Byte
        strmFile.Read(abyBuffer, 0, abyBuffer.Length)

        Dim sFile As String = Path.GetFileName(strFile)
        Dim theEntry As ZipEntry = New ZipEntry(sFile)
        theEntry.DateTime = DateTime.Now
        theEntry.Size = strmFile.Length
        strmFile.Close()

        objCrc32.Reset()
        objCrc32.Update(abyBuffer)
        theEntry.Crc = objCrc32.Value

        strmZipOutputStream.PutNextEntry(theEntry)
        strmZipOutputStream.Write(abyBuffer, 0, abyBuffer.Length)

        'IO.File.Delete(strFile)
    Next

    strmZipOutputStream.Finish()

    Return outputMemStream

End Function

WriteMemoryStreamToDisk:

Public Shared Sub WriteMemoryStreamToDisk(outputMemStream As MemoryStream, file As String)

    Dim buffer As Byte() = outputMemStream.ToArray()
    Dim ms As New MemoryStream(buffer)
    Dim newFile As New FileStream(file, FileMode.Create, FileAccess.Write)
    ms.WriteTo(newFile)
    newFile.Close()
    ms.Close()

End Sub

可能出了什么问题?有帮助吗?

在这种情况下,我通常首先做的是在文本查看器中打开“损坏的”文件,并确定假定的(文件类型)文件是否实际上是一个(文件类型)文件。事实往往并非如此。例如。查看常规 ZIP 存档时,前 2 个字符 必须 是“PK”,文件的其余部分是二进制“乱码”。 PDF 类似:前几个字符是“%PDF-(PDF 版本)”,例如"%PDF-1.7".

尤其是下载时,您最终可能会得到与预期不同的东西,例如右键单击文件 link -> “另存为”。事实证明,它不是直接 link 到文件,而是某种将实际文件推送到客户端的脚本。当您将 link“另存为”时,您得到的是脚本的 HTML 输出,而不是文件本身。

还有很多反恶意软件监控网络流量并用其他东西替换可疑文件。

您可能已经“沦为猎物”了。

好的,我终于找到了问题的根源,我会自己回答,希望对遇到同样问题的其他人有所帮助。

问题出在 aspx“UpdatePanel”的工作方式上,它执行部分回发,这与响应对象不兼容并阻止它正常工作。

解决方案是禁用导致问题的特定元素的部分回发,在我的例子中:

添加它会导致 aDownloadPdfs link 执行完整的回发,所有 Response 对象方法将按预期工作。