#vb.net #download #stream #response #zipoutputstream
Вопрос:
У меня есть список строк в формате PDF со строками в виде «http://whatever.pdf» и нужно создать их zip-файл и передать его клиенту в качестве загрузки.
Странно то, что если я создам zip (я использую ZipOutputStream) и запишу файл на диск, он работает, я смогу открыть сгенерированный zip-файл и распаковать его без проблем, но если я передам его (что мне нужно сделать) Я получаю zip-файл того же размера, но который выдает ошибку при попытке его открыть.
CreateZip:
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() amp; ".zip" outputMemStream.Position = 0 'Utility.WriteMemoryStreamToDisk(outputMemStream, fileRoot amp; "" amp; zipName) =gt; This line creates a valid zip file on disk, but I need to avoid it. Response.AddHeader("Content-Length", outputMemStream.Length) Response.Write(outputMemStream) =gt; 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
Генерировать поток вывода:
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
Что может быть не так? Какая-нибудь помощь?
Ответ №1:
Что я всегда делаю в первую очередь в таких случаях, так это открываю «поврежденный» файл в программе просмотра текста и выясняю, действительно ли файл предположительно (типа файла) является файлом (типа файла). Часто оказывалось, что это не так. Например, при просмотре обычного ZIP-архива первые 2 символа должны быть «PK», остальная часть файла-двоичная «тарабарщина». Аналогично для PDF-файлов: первые несколько символов «%PDF-(версия PDF)«, например «%PDF-1.7».
Особенно при загрузке, вы можете получить что-то другое, чем вы ожидаете, например, щелкнув правой кнопкой мыши ссылку на файл -gt; «Сохранить как». Оказывается, это не прямая ссылка на файл, а какой-то скрипт, который отправляет фактический файл клиенту. То, что вы получаете, когда «Сохраняете как» эту ссылку, — это вывод HTML из сценария, а не сам файл.
Существует также множество антивирусных программ, отслеживающих веб-трафик и заменяющих подозрительный файл чем-то другим.
Возможно, вы «стали жертвой» чего-то подобного.
Комментарии:
1. Спасибо за ваш ответ @Hel O’Tween. Я обнаружил, что, к моему удивлению, загруженный zip-файл (с правильным размером) содержит весь html-код aspx. Не знаю почему, но это определенно не zip-файл, но я не могу понять, почему, если я запишу файл на диск внутри webroot, он создаст действительный и рабочий zip-файл!
2. @DiegoPerez, который предполагает, что страница отображается до
CreateZip
вызова метода. Для загрузки лучше использовать обработчик (.ashx), а не страницу (.aspx), потому что в первом случае нет всех рамок второго.
Ответ №2:
Хорошо, поскольку я наконец нашел корень своей проблемы, я отвечу сам и надеюсь быть полезным всем, кто столкнется с той же проблемой.
Проблема заключается в том, как работает aspx «UpdatePanel», он выполняет частичную обратную передачу, что несовместимо с объектом ответа и мешает ему работать правильно.
Решение состоит в том, чтобы отключить частичную обратную передачу для конкретного элемента, вызывающего проблему, в моем случае:
Добавление этого приведет к тому, что ссылка aDownloadPdfs выполнит полную обратную передачу, и все методы объекта ответа будут работать должным образом.