Adding multiple files to an in memory zip archive in c# - c#

I'm trying to use the Zip Archive library in .NET 4.5 to create a .zip file in memory of a bunch of byte[] attachments:
using (var memoryStream = new MemoryStream())
{
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
string zipFilename = string.Format(#"c:\temp\{0} - {1}.zip",
"test",
System.DateTime.Now.ToString("yyyyMMddHHmm"));
using (var fileStream = new FileStream(zipFilename, FileMode.Create))
{
foreach (var attachment in attachments)
{
ZipArchiveEntry entry = archive.CreateEntry(attachment.FileName);
using (Stream ZipFile = entry.Open())
{
byte[] data = attachment.Data;
ZipFile.Write(data, 0, data.Length);
}
}
}
}
}
PdfAttachment is a class with a byte[] Data and string Filename.
My problem is twofold. Once, the zip archive is empty. 2, rather than save it to a file, I'd like to use the response outputs to download the file in the users browser, which I have tried with:
Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", string.Format("attachment;filename={0}.zip; size={1}", "test.zip", memoryStream.Length));
Response.BinaryWrite(memoryStream);
Response.Flush();
Response.End();
I haven't been able to find many examples online, hence the vagueness.

The fileStream is never written to because it is not associated with the archive.
So the archive is being written to the memoryStream.
BinaryWrite only accepts a byte[] so use memoryStream.ToArray().
Also, Response.ContentType value is wrong.

Related

FileResult content-length mismatch

Hi im using the code in this blogpost :
https://blog.stephencleary.com/2016/11/streaming-zip-on-aspnet-core.html
In order to stream a zip file with .Net core. I made it work but since i did not add the content-length header in the response when i donwload the zip file, it won't show the download progress in chrome. Since i know in advance the zip file size I can actually set the content-length header, with the SetHeadersAndLog method
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.internal.fileresultexecutorbase.setheadersandlog?view=aspnetcore-2.0
but when i do so I have the following error :
System.InvalidOperationException: Response Content-Length mismatch: too many bytes written (144144633 of 144144627).
Any idea why the response is not the same length as the zip file ?
Here's the code to serve the file:
this._httpContext.Response.ContentType = "application/octet-stream";
this._httpContext.Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");
this._httpContext.Response.ContentLength = estimatedFileSize;
FileCallbackResult result = new FileCallbackResult(new MediaTypeHeaderValue("application/octet-stream"), estimatedFileSize, async (outputStream, _) =>
{
using (ZipArchive zip = new ZipArchive(outputStream, ZipArchiveMode.Create, false))
{
foreach (string filepath in Directory.EnumerateFiles(existingDirectory.FullName, "*.*", SearchOption.AllDirectories))
{
string relativepath = filepath.Replace(existingDirectory.FullName + "\\", string.Empty);
ZipArchiveEntry zipEntry = zip.CreateEntry(relativepath, CompressionLevel.Fastest);
using (Stream zipstream = zipEntry.Open())
{
using (Stream stream = new FileStream(filepath, FileMode.Open))
{
await stream.CopyToAsync(zipstream);
}
}
}
}
})
{
FileDownloadName = $"{package.FileName}.zip",
};
You need to seek the stream back to the beginning.

How to download multiple files stored in database as bytes

I am storing files in database in the form of bytes. We have requirement to download all attachments as zip file. Please suggest
Try this
protected void ZipDownload()
{
var list = //query for getting the files.
ZipFile zip = new ZipFile();
foreach (var file in list)
{
zip.AddEntry(file.docname, (byte[])file.doc.ToArray());
}
var zipMs = new MemoryStream();
zip.Save(zipMs);
byte[] fileData = zipMs.GetBuffer();
zipMs.Seek(0, SeekOrigin.Begin);
zipMs.Flush();
Response.Clear();
Response.AddHeader("content-disposition", "attachment;filename=docs.zip ");
Response.ContentType = "application/zip";
Response.BinaryWrite(fileData);
Response.End();
}

ZipStorer - Zip Text in MemoryStream, Transmit through httpResponse, unable open as Zip File

Note: I have solved the problem myself. See the below answer.
I'm using ZipStorer to zip files in ASP.NET C# 4.0 WebForm.
After I created the Zip in MemoryStream and transmitted it using httpResponse, the client user was unable to open the file as a Zip File.
Any tips? Thanks.
Below is my code:
string text = GetLongText();
byte[] ba = Encoding.UTF8.GetBytes(text);
using (MemoryStream ms = new MemoryStream())
{
using (ZipStorer zip = ZipStorer.Create(ms, "My Zip File"))
{
zip.AddStream(ZipStorer.Compression.Deflate, "MyText.txt", new MemoryStream(ba), DateTime.Now, "My Text");
Response.Clear();
Response.AppendHeader("content-disposition", "attachment; filename=MyZip.zip");
Response.ContentType = "application/zip";
ms.WriteTo(Response.OutputStream);
Response.End();
}
}
I have solve the problem myself. Below is the codes:
string text = GetLongText();
byte[] ba = Encoding.UTF8.GetBytes(text);
using (MemoryStream ms = new MemoryStream())
{
using (ZipStorer zip = ZipStorer.Create(ms, "My Zip"))
{
zip.AddStream(ZipStorer.Compression.Deflate, "text.txt", new MemoryStream(ba), DateTime.Now, "My Text");
}
Response.AppendHeader("content-disposition", "attachment; filename=MyZip.zip");
Response.ContentType = "application/zip";
Response.BinaryWrite(ms.ToArray());
Response.End();
}
}

Download multiple Mp3 files from different urls as zip archive in asp.Net

I am working on a .Net Application in which i need to add multiple mp3 files to a zip archive and download the zip archive locally. The mp3 files are on different urls ad are not hosted or stored on my server. Which library is good for such thing. I tried using SharpLipZip but failed. Here is my code which i am currently trying to use with sharpziplib. All the code is executed but browser doesnt download.
string[] fileURLs = new string[] { "http://www.musicimpressions.com/demos_mp3g/d_RE41843.mp3", "http://media.archambault.ca/sample/6/2/B/0/62B0CC2D91D4357D6477845E967AF9BA/00000000000000027923-256K_44S_2C_cbr1x_clipped.mp3" };
Response.AddHeader("Content-Disposition", "attachment; filename=CallRecordings.zip");
Response.ContentType = "application/x-zip-compressed";
ZipOutputStream zipStream = new ZipOutputStream(Response.OutputStream);
zipStream.SetLevel(3);
byte[] buffer = new byte[10485760];
foreach (string url in fileURLs)
{
Stream fileStream = null;
HttpWebRequest fileReq = (HttpWebRequest)HttpWebRequest.Create(url);
HttpWebResponse fileResp = (HttpWebResponse)fileReq.GetResponse();
if (fileReq.ContentLength > 0)
fileResp.ContentLength = fileReq.ContentLength;
//Get the Stream returned from the response
fileStream = fileResp.GetResponseStream();
byte[] fileBytes = ReadStream(fileStream);
ZipEntry fileEntry = new ZipEntry(ZipEntry.CleanName(url));
fileEntry.Size = fileBytes.Length;
zipStream.PutNextEntry(fileEntry);
zipStream.Write(fileBytes, 0, fileBytes.Length);
Response.Flush();
fileStream.Close();
}
zipStream.Finish();
zipStream.Flush();
zipStream.Close();
Response.Flush();
Response.End();
The definition of ReadStream is as follows.
public static byte[] ReadStream(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
Well, thats the same thing which I am also building for my website, anyhow i was trying to look for the zip file structure first to create the zip file manually instead of using any other library. Until now, i am only able to get the structure of the zip file :
https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip.html
Here, it mentions that you need to have the CRC32 of the file first which is being appended to the zip file, so thats the tricky part in my side. Let me know once you gets any updates for the same.
Good Luck :)

c# - DotNetZip open zip file from MemoryStream

What I like to do is instead of storing a zip file on disk, I like to open it up from a MemoryStream.
I am looking at the documentation for DotNetZip programming example:
Note that I tweaked it slightly based on what I thought may be needed.
var ms = new MemoryStream();
using (ZipFile zip = new ZipFile())
{
zip.AddFile("ReadMe.txt");
zip.AddFile("7440-N49th.png");
zip.AddFile("2008_Annual_Report.pdf");
zip.Save(ms); // this will save the files in memory steam
}
// now what I need is for the zip file to open up so that
the user can view all the files in it. Not sure what to do next after
zip.Save(ms) for this to happen.
Try this:
public ActionResult Index()
{
var memoryStream = new MemoryStream();
using (var zip = new ZipFile())
{
zip.AddFile("ReadMe.txt");
zip.AddFile("7440-N49th.png");
zip.AddFile("2008_Annual_Report.pdf");
zip.Save(memoryStream);
}
memoryStream.Seek(0, 0);
return File(memoryStream, "application/octet-stream", "archive.zip");
}
If this is local. you will need to save the stream in to the file and call Process.Start on it.
If this is on server. Just write your ms into Response with appropriate mime type.
You'd have to send the content of the memory stream back as the response:
using (MemoryStream ms = new MemoryStream())
{
using (ZipFile zip = new ZipFile())
{
zip.AddFile("ReadMe.txt");
zip.AddFile("7440-N49th.png");
zip.AddFile("2008_Annual_Report.pdf");
zip.Save(ms); // this will save the files in memory steam
}
context.Response.ContentType = "application/zip";
context.Response.AddHeader("Content-Length", ms.Size);
context.Response.AddHeader("Content-disposition", "attachment; filename=MyZipFile.zip");
ms.Seek(0, SeekOrigin.Begin);
ms.WriteTo(context.Response.OutputStream);
}
Try creating an ActionResult a bit like this:
I'm not 100% sure about the line var fileData = ms; and i don't have access to a dev environment just now, but there should be enough for you to work it out.
public ActionResult DownloadZip()
{
using (MemoryStream ms = new MemoryStream())
{
using (ZipFile zip = new ZipFile())
{
zip.AddFile("ReadMe.txt");
zip.AddFile("7440-N49th.png");
zip.AddFile("2008_Annual_Report.pdf");
zip.Save(ms); // this will save the files in memory steam
}
byte[] fileData = ms.GetBuffer();// I think this will work. Last time I did it, I did something like this instead... Zip.CreateZip("LogPosts.csv", System.Text.Encoding.UTF8.GetBytes(csv));
var cd = new System.Net.Mime.ContentDisposition
{
FileName = "Whatever.zip",
// always prompt the user for downloading, set to true if you want
// the browser to try to show the file inline
Inline = false,
};
Response.AppendHeader("Content-Disposition", cd.ToString());
return File(fileData, "application/octet-stream");
}
}
this way we can write zip to output stream. may help
ZipFile zip = new ZipFile();
List<Attachment> listattachments = email.Attachments;
int acount = attachments.Count;
for (int i = 0; i < acount; i++)
{
zip.AddEntry(attachments[i].FileName, listattachments[i].Content);
}
Response.Clear();
Response.BufferOutput = false;
string zipName = String.Format("{0}.zip", message.Headers.From.DisplayName);
Response.ContentType = "application/zip";
Response.AddHeader("content-disposition", "attachment; filename=" + zipName);
zip.Save(Response.OutputStream);
Response.End();

Categories