Are .zip files ever going away? I remember back in the 90’s using WinZip as an alternative to the PKZip command line option. Anyway, fast forward 20+ years, and ZIP is still common and a great way to package files. Long story short: AWS Elastic Beanstalk allows you to easily deploy apps using a .zip file (if you haven’t tried Elastic Beanstalk – it’s pretty awesome) and I wanted a faster way to create a .zip of an app. (Yes, I know it’s not the best way to deploy like Git or the API).
There is a bunch of great sample code out there for creating ZIP archives in c# .Net using the ZipArchive Class in System.IO.Compression, but nothing seems to be a complete sample, showing multiple files. Below is what I’ve been using. One difference in this is changing the path separators from backslashes to forward-slashes. Without this, AWS wasn’t able to extract my .zip archive. I would see errors such as:
warning: .... source_bundle appears to use backslashes as path separators (ElasticBeanstalk::ExternalInvocationError) (Executor::NonZeroExitStatus) [Application update ...01_unzip.sh] : Activity failed.
Anyway, here it is:
First, make sure to reference these two:
And at the top of your code file include:
using System.IO;
using System.IO.Compression;
And the basic code is below. Feel free to ask any questions in the comments.
//what folder to zip - include trailing slash string dirRoot = @"c:\yourfolder\"; //get a list of files string[] filesToZip = Directory.GetFiles(dirRoot, "*.*", SearchOption.AllDirectories); //final archive name (I use date / time) string zipFileName = string.Format("zipfile-{0:yyyy-MM-dd_hh-mm-ss-tt}.zip", DateTime.Now); using (MemoryStream zipMS = new MemoryStream()) { using (ZipArchive zipArchive = new ZipArchive(zipMS, ZipArchiveMode.Create, true)) { //loop through files to add foreach (string fileToZip in filesToZip) { //exclude some files? -I don't want to ZIP other .zips in the folder. if (new FileInfo(fileToZip).Extension == ".zip") continue; //exclude some file names maybe? if (fileToZip.Contains("node_modules")) continue; //read the file bytes byte[] fileToZipBytes = System.IO.File.ReadAllBytes(fileToZip); //create the entry - this is the zipped filename //change slashes - now it's VALID ZipArchiveEntry zipFileEntry = zipArchive.CreateEntry(fileToZip.Replace(dirRoot, "").Replace('\\', '/')); //add the file contents using (Stream zipEntryStream = zipFileEntry.Open()) using (BinaryWriter zipFileBinary = new BinaryWriter(zipEntryStream)) { zipFileBinary.Write(fileToZipBytes); } //lstLog.Items.Add("zipped: " + fileToZip); } } using (FileStream finalZipFileStream = new FileStream(@"c:\whateverfolder\Deploy_" + zipFileName, FileMode.Create)) { zipMS.Seek(0, SeekOrigin.Begin); zipMS.CopyTo(finalZipFileStream); } //lstLog.Items.Add("ZIP Archive Created."); }
Is this available on Framework 4?
LikeLike
Yes. That’s what I’m using.
LikeLike
I am curious to know why you didn’t use the CreateEntryFromFile to add your files to the zip file, something like
foreach (string fileName in todaysFiles) //todaysFiles is list of file names (with full path) to be zipped
{
//zipPath is the name of the zip file with full path
using (ZipArchive archive = ZipFile.Open(zipPath, ZipArchiveMode.Update))
{
archive.CreateEntryFromFile(fileName, Path.GetFileName(fileName));
}
}
or what I guess I am really wondering – is the process using streams faster?
LikeLike
So at first I used this because it was easy, but I found that AWS (EB) didn’t accept the files. I’m not sure why, but I believe it has to do with the handling of files in sub-directories and how their indicated in the .zip file.
This seemed to be the start of it.
//change slashes – now it’s VALID
ZipArchiveEntry zipFileEntry = zipArchive.CreateEntry(fileToZip.Replace(dirRoot, “”).Replace(‘\\’, ‘/’));
But maybe this works without Stream as well.
LikeLike
what a nice code …for last 2 days i am trying….thanku chris……..but it is not working without Stream
LikeLike