Zip folder in C# - c#

What is an example (simple code) of how to zip a folder in C#?
Update:
I do not see namespace ICSharpCode. I downloaded ICSharpCode.SharpZipLib.dll but I do not know where to copy that DLL file. What do I need to do to see this namespace?
And do you have link for that MSDN example for compress folder, because I read all MSDN but I couldn't find anything.
OK, but I need next information.
Where should I copy ICSharpCode.SharpZipLib.dll to see that namespace in Visual Studio?

This answer changes with .NET 4.5. Creating a zip file becomes incredibly easy. No third-party libraries will be required.
string startPath = #"c:\example\start";
string zipPath = #"c:\example\result.zip";
string extractPath = #"c:\example\extract";
ZipFile.CreateFromDirectory(startPath, zipPath);
ZipFile.ExtractToDirectory(zipPath, extractPath);

From the DotNetZip help file, http://dotnetzip.codeplex.com/releases/
using (ZipFile zip = new ZipFile())
{
zip.UseUnicodeAsNecessary= true; // utf-8
zip.AddDirectory(#"MyDocuments\ProjectX");
zip.Comment = "This zip was created at " + System.DateTime.Now.ToString("G") ;
zip.Save(pathToSaveZipFile);
}

There's nothing in the BCL to do this for you, but there are two great libraries for .NET which do support the functionality.
SharpZipLib
DotNetZip
I've used both and can say that the two are very complete and have well-designed APIs, so it's mainly a matter of personal preference.
I'm not sure whether they explicitly support adding Folders rather than just individual files to zip files, but it should be quite easy to create something that recursively iterated over a directory and its sub-directories using the DirectoryInfo and FileInfo classes.

In .NET 4.5 the ZipFile.CreateFromDirectory(startPath, zipPath); method does not cover a scenario where you wish to zip a number of files and sub-folders without having to put them within a folder. This is valid when you wish the unzip to put the files directly within the current folder.
This code worked for me:
public static class FileExtensions
{
public static IEnumerable<FileSystemInfo> AllFilesAndFolders(this DirectoryInfo dir)
{
foreach (var f in dir.GetFiles())
yield return f;
foreach (var d in dir.GetDirectories())
{
yield return d;
foreach (var o in AllFilesAndFolders(d))
yield return o;
}
}
}
void Test()
{
DirectoryInfo from = new DirectoryInfo(#"C:\Test");
using (var zipToOpen = new FileStream(#"Test.zip", FileMode.Create))
{
using (var archive = new ZipArchive(zipToOpen, ZipArchiveMode.Create))
{
foreach (var file in from.AllFilesAndFolders().OfType<FileInfo>())
{
var relPath = file.FullName.Substring(from.FullName.Length+1);
ZipArchiveEntry readmeEntry = archive.CreateEntryFromFile(file.FullName, relPath);
}
}
}
}
Folders don't need to be "created" in the zip-archive. The second parameter "entryName" in CreateEntryFromFile should be a relative path, and when unpacking the zip-file the directories of the relative paths will be detected and created.

There is a ZipPackage class in the System.IO.Packaging namespace which is built into .NET 3, 3.5, and 4.0.
http://msdn.microsoft.com/en-us/library/system.io.packaging.zippackage.aspx
Here is an example how to use it.
http://www.codeproject.com/KB/files/ZipUnZipTool.aspx?display=Print

There's an article over on MSDN that has a sample application for zipping and unzipping files and folders purely in C#. I've been using some of the classes in that successfully for a long time. The code is released under the Microsoft Permissive License, if you need to know that sort of thing.
EDIT: Thanks to Cheeso for pointing out that I'm a bit behind the times. The MSDN example I pointed to is in fact using DotNetZip and is really very fully-featured these days. Based on my experience of a previous version of this I'd happily recommend it.
SharpZipLib is also quite a mature library and is highly rated by people, and is available under the GPL license. It really depends on your zipping needs and how you view the license terms for each of them.
Rich

using DotNetZip (available as nuget package):
public void Zip(string source, string destination)
{
using (ZipFile zip = new ZipFile
{
CompressionLevel = CompressionLevel.BestCompression
})
{
var files = Directory.GetFiles(source, "*",
SearchOption.AllDirectories).
Where(f => Path.GetExtension(f).
ToLowerInvariant() != ".zip").ToArray();
foreach (var f in files)
{
zip.AddFile(f, GetCleanFolderName(source, f));
}
var destinationFilename = destination;
if (Directory.Exists(destination) && !destination.EndsWith(".zip"))
{
destinationFilename += $"\\{new DirectoryInfo(source).Name}-{DateTime.Now:yyyy-MM-dd-HH-mm-ss-ffffff}.zip";
}
zip.Save(destinationFilename);
}
}
private string GetCleanFolderName(string source, string filepath)
{
if (string.IsNullOrWhiteSpace(filepath))
{
return string.Empty;
}
var result = filepath.Substring(source.Length);
if (result.StartsWith("\\"))
{
result = result.Substring(1);
}
result = result.Substring(0, result.Length - new FileInfo(filepath).Name.Length);
return result;
}
Usage:
Zip(#"c:\somefolder\subfolder\source", #"c:\somefolder2\subfolder2\dest");
Or
Zip(#"c:\somefolder\subfolder\source", #"c:\somefolder2\subfolder2\dest\output.zip");

Following code uses a third-party ZIP component from Rebex:
// add content of the local directory C:\Data\
// to the root directory in the ZIP archive
// (ZIP archive C:\archive.zip doesn't have to exist)
Rebex.IO.Compression.ZipArchive.Add(#"C:\archive.zip", #"C:\Data\*", "");
Or if you want to add more folders without need to open and close archive multiple times:
using Rebex.IO.Compression;
...
// open the ZIP archive from an existing file
ZipArchive zip = new ZipArchive(#"C:\archive.zip", ArchiveOpenMode.OpenOrCreate);
// add first folder
zip.Add(#"c:\first\folder\*","\first\folder");
// add second folder
zip.Add(#"c:\second\folder\*","\second\folder");
// close the archive
zip.Close(ArchiveSaveAction.Auto);
You can download the ZIP component here.
Using a free, LGPL licensed SharpZipLib is a common alternative.
Disclaimer: I work for Rebex

"Where should I copy ICSharpCode.SharpZipLib.dll to see that namespace in Visual Studio?"
You need to add the dll file as a reference in your project. Right click on References in the Solution Explorer->Add Reference->Browse and then select the dll.
Finally you'll need to add it as a using statement in whatever files you want to use it in.

ComponentPro ZIP can help you achieve that task. The following code snippet compress files and dirs in a folder. You can use wilcard mask as well.
using ComponentPro.Compression;
using ComponentPro.IO;
...
// Create a new instance.
Zip zip = new Zip();
// Create a new zip file.
zip.Create("test.zip");
zip.Add(#"D:\Temp\Abc"); // Add entire D:\Temp\Abc folder to the archive.
// Add all files and subdirectories from 'c:\test' to the archive.
zip.AddFiles(#"c:\test");
// Add all files and subdirectories from 'c:\my folder' to the archive.
zip.AddFiles(#"c:\my folder", "");
// Add all files and subdirectories from 'c:\my folder' to '22' folder within the archive.
zip.AddFiles(#"c:\my folder2", "22");
// Add all .dat files from 'c:\my folder' to '22' folder within the archive.
zip.AddFiles(#"c:\my folder2", "22", "*.dat");
// Or simply use this to add all .dat files from 'c:\my folder' to '22' folder within the archive.
zip.AddFiles(#"c:\my folder2\*.dat", "22");
// Add *.dat and *.exe files from 'c:\my folder' to '22' folder within the archive.
zip.AddFiles(#"c:\my folder2\*.dat;*.exe", "22");
TransferOptions opt = new TransferOptions();
// Donot add empty directories.
opt.CreateEmptyDirectories = false;
zip.AddFiles(#"c:\abc", "/", opt);
// Close the zip file.
zip.Close();
http://www.componentpro.com/doc/zip has more examples

Related

Create a directory in a zipFile and add files using C#

The files I want to zip are in different folders
The folder structure is as follows:
FileId/FileType/File.extension
FileId/FileType/File.extension
I'm trying to create a zip with the following structure
FileType/File.extension
FileType/File.extension
I have tried a stackoverflow link but couldn't get it to work in my scenario.
I have the files in the zip directly. But I couldn't find a good source to have the files in a specific folder.
Code I have referred from previous posts:
using (ZipArchive archive = ZipFile.Open(zipPath + #"\release.zip", ZipArchiveMode.Update))
{
ZipArchiveEntry readmeEntry;
DirectoryInfo d = new DirectoryInfo(folderToAdd);
FileInfo[] Files = d.GetFiles("*");
foreach (FileInfo file in Files)
{
archive.CreateEntry(preset.FileFormat);
readmeEntry = archive.CreateEntryFromFile(newFile, fileName);
}
}
I also tried creating a zip file in update mode and then as follows:
ZipFile.Open(zipPath + #"\release.zip", ZipArchiveMode.Update);
ZipFile.CreateFromDirectory(folderToAdd, zipPath + #"\release.zip", CompressionLevel.Fastest, true);
But the CreateFromDir breaks with an exception saying that the release.zip already exists.
Should I copy my files into respective folders and then apply the CreateFromDir method, or there is a better way to do this without re-copying and then CreateFromDir on top.

Opening Split Zip Files With DotNetZip

I am trying to extract files from zip files using the DotNetZip library. I am able to extract files when it is a single .zip file. However, when I try to extract files from a multi volume zip file like Something.zip.0 or Something.zip.1, I get the following two exceptions:
-Exception thrown: 'Ionic.Zip.BadReadException' in Ionic.Zip.dll
-Exception thrown: 'Ionic.Zip.ZipException' in Ionic.Zip.dll
Is it possible for DotNetZip to read these type of files, or should I be looking into an alternative approach? I am working on Visual Studios using C#.
Here's a snippet of how I implement my zip file extraction.
using (Ionic.Zip.ZipFile zip = Ionic.Zip.ZipFile.Read(_pathToZip))
{
zip.CompressionLevel = Ionic.Zlib.CompressionLevel.BestSpeed;
foreach(Ionic.Zip.ZipEntry ze in zip)
{
string fileName = ze.FileName;
bool isThereItemToExtract = isThereMatch(fileName.ToLower(), _folderList, _fileList);
if (isThereItemToExtract)
{
string pathOfFileToExtract = (_destinationPath + "\\" + ze.FileName).Replace('/', '\\');
string pathInNewZipFile = goUpOneDirectoryRelative(ze.FileName);
ze.Extract(_destinationPath, Ionic.Zip.ExtractExistingFileAction.OverwriteSilently);
_newZip.AddItem(pathOfFileToExtract, pathInNewZipFile);
}
}
_newZip.Save();
}
Please refer the DotNetZipLibrary code examples:
using Ionic.Zip;
private void MyExtract(string zipToUnpack, string unpackDirectory)
{
using (ZipFile zip1 = ZipFile.Read(zipToUnpack))
{
// here, we extract every entry, but we could extract conditionally
// based on entry name, size, date, checkbox status, etc.
foreach (ZipEntry e in zip1)
{
e.Extract(unpackDirectory, ExtractExistingFileAction.OverwriteSilently);
}
}
}
This method should be able to extract either split and not split zip files.
Every zip entry will be extracted with its full path as specified in the zip archive, relative to the current unpackDirectory.
There's no need to check if zip entry exsists (isThereItemToExtract). Interating the zip entries with foreach should do the job.
To avoid collisions you need to check if file with same name as zipEntry exsists in the unpackDirectory, or use ExtractExistingFileAction.OverwriteSilently flag.
Is it possible for DotNetZip to read these type of files, or should I be looking into an alternative approach? I am working on Visual Studios using C#.
In my experience, this is the best library to deal with split zip files.

C# Access text file in zip archive

How can I read content of a text file inside a zip archive?
For example I have an archive qwe.zip, and insite it there's a file asd.txt, so how can I read contents of that file?
Is it possible to do without extracting the whole archive? Because it need to be done quick, when user clicks a item in a list, to show description of the archive (it needed for plugin system for another program). So extracting a whole archive isn't the best solution... because it might be few Mb, which will take at least few seconds or even more to extract... while only that single file need to be read.
You could use a library such as SharpZipLib or DotNetZip to unzip the file and fetch the contents of individual files contained inside. This operation could be performed in-memory and you don't need to store the files into a temporary folder.
Unzip to a temp-folder take the file and delete the temp-data
public static void Decompress(string outputDirectory, string zipFile)
{
try
{
if (!File.Exists(zipFile))
throw new FileNotFoundException("Zip file not found.", zipFile);
Package zipPackage = ZipPackage.Open(zipFile, FileMode.Open, FileAccess.Read);
foreach (PackagePart part in zipPackage.GetParts())
{
string targetFile = outputDirectory + "\\" + part.Uri.ToString().TrimStart('/');
using (Stream streamSource = part.GetStream(FileMode.Open, FileAccess.Read))
{
using (Stream streamDestination = File.OpenWrite(targetFile))
{
Byte[] arrBuffer = new byte[10000];
int iRead = streamSource.Read(arrBuffer, 0, arrBuffer.Length);
while (iRead > 0)
{
streamDestination.Write(arrBuffer, 0, iRead);
iRead = streamSource.Read(arrBuffer, 0, arrBuffer.Length);
}
}
}
}
}
catch (Exception)
{
throw;
}
}
Although late in the game and the question is already answered, in hope that this still might be useful for others who find this thread, I would like to add another solution.
Just today I encountered a similar problem when I wanted to check the contents of a ZIP file with C#. Other than NewProger I cannot use a third party library and need to stay within the out-of-the-box .NET classes.
You can use the System.IO.Packaging namespace and use the ZipPackage class. If it is not already included in the assembly, you need to add a reference to WindowsBase.dll.
It seems, however, that this class does not always work with every Zip file. Calling GetParts() may return an empty list although in the QuickWatch window you can find a property called _zipArchive that contains the correct contents.
If this is the case for you, you can use Reflection to get the contents of it.
On geissingert.com you can find a blog article ("Getting a list of files from a ZipPackage") that gives a coding example for this.
SharpZipLib or DotNetZip may still need to get/read the whole .zip file to unzip a file. Actually, there is still method could make you just extract special file from the .zip file without reading the entire .zip file but just reading small segment.
I needed to have insights into Excel files, I did it like so:
using (var zip = ZipFile.Open("ExcelWorkbookWithMacros.xlsm", ZipArchiveMode.Update))
{
var entry = zip.GetEntry("xl/_rels/workbook.xml.rels");
if (entry != null)
{
var tempFile = Path.GetTempFileName();
entry.ExtractToFile(tempFile, true);
var content = File.ReadAllText(tempFile);
[...]
}
}

Zipping Directory using zlib [duplicate]

What is an example (simple code) of how to zip a folder in C#?
Update:
I do not see namespace ICSharpCode. I downloaded ICSharpCode.SharpZipLib.dll but I do not know where to copy that DLL file. What do I need to do to see this namespace?
And do you have link for that MSDN example for compress folder, because I read all MSDN but I couldn't find anything.
OK, but I need next information.
Where should I copy ICSharpCode.SharpZipLib.dll to see that namespace in Visual Studio?
This answer changes with .NET 4.5. Creating a zip file becomes incredibly easy. No third-party libraries will be required.
string startPath = #"c:\example\start";
string zipPath = #"c:\example\result.zip";
string extractPath = #"c:\example\extract";
ZipFile.CreateFromDirectory(startPath, zipPath);
ZipFile.ExtractToDirectory(zipPath, extractPath);
From the DotNetZip help file, http://dotnetzip.codeplex.com/releases/
using (ZipFile zip = new ZipFile())
{
zip.UseUnicodeAsNecessary= true; // utf-8
zip.AddDirectory(#"MyDocuments\ProjectX");
zip.Comment = "This zip was created at " + System.DateTime.Now.ToString("G") ;
zip.Save(pathToSaveZipFile);
}
There's nothing in the BCL to do this for you, but there are two great libraries for .NET which do support the functionality.
SharpZipLib
DotNetZip
I've used both and can say that the two are very complete and have well-designed APIs, so it's mainly a matter of personal preference.
I'm not sure whether they explicitly support adding Folders rather than just individual files to zip files, but it should be quite easy to create something that recursively iterated over a directory and its sub-directories using the DirectoryInfo and FileInfo classes.
In .NET 4.5 the ZipFile.CreateFromDirectory(startPath, zipPath); method does not cover a scenario where you wish to zip a number of files and sub-folders without having to put them within a folder. This is valid when you wish the unzip to put the files directly within the current folder.
This code worked for me:
public static class FileExtensions
{
public static IEnumerable<FileSystemInfo> AllFilesAndFolders(this DirectoryInfo dir)
{
foreach (var f in dir.GetFiles())
yield return f;
foreach (var d in dir.GetDirectories())
{
yield return d;
foreach (var o in AllFilesAndFolders(d))
yield return o;
}
}
}
void Test()
{
DirectoryInfo from = new DirectoryInfo(#"C:\Test");
using (var zipToOpen = new FileStream(#"Test.zip", FileMode.Create))
{
using (var archive = new ZipArchive(zipToOpen, ZipArchiveMode.Create))
{
foreach (var file in from.AllFilesAndFolders().OfType<FileInfo>())
{
var relPath = file.FullName.Substring(from.FullName.Length+1);
ZipArchiveEntry readmeEntry = archive.CreateEntryFromFile(file.FullName, relPath);
}
}
}
}
Folders don't need to be "created" in the zip-archive. The second parameter "entryName" in CreateEntryFromFile should be a relative path, and when unpacking the zip-file the directories of the relative paths will be detected and created.
There is a ZipPackage class in the System.IO.Packaging namespace which is built into .NET 3, 3.5, and 4.0.
http://msdn.microsoft.com/en-us/library/system.io.packaging.zippackage.aspx
Here is an example how to use it.
http://www.codeproject.com/KB/files/ZipUnZipTool.aspx?display=Print
There's an article over on MSDN that has a sample application for zipping and unzipping files and folders purely in C#. I've been using some of the classes in that successfully for a long time. The code is released under the Microsoft Permissive License, if you need to know that sort of thing.
EDIT: Thanks to Cheeso for pointing out that I'm a bit behind the times. The MSDN example I pointed to is in fact using DotNetZip and is really very fully-featured these days. Based on my experience of a previous version of this I'd happily recommend it.
SharpZipLib is also quite a mature library and is highly rated by people, and is available under the GPL license. It really depends on your zipping needs and how you view the license terms for each of them.
Rich
using DotNetZip (available as nuget package):
public void Zip(string source, string destination)
{
using (ZipFile zip = new ZipFile
{
CompressionLevel = CompressionLevel.BestCompression
})
{
var files = Directory.GetFiles(source, "*",
SearchOption.AllDirectories).
Where(f => Path.GetExtension(f).
ToLowerInvariant() != ".zip").ToArray();
foreach (var f in files)
{
zip.AddFile(f, GetCleanFolderName(source, f));
}
var destinationFilename = destination;
if (Directory.Exists(destination) && !destination.EndsWith(".zip"))
{
destinationFilename += $"\\{new DirectoryInfo(source).Name}-{DateTime.Now:yyyy-MM-dd-HH-mm-ss-ffffff}.zip";
}
zip.Save(destinationFilename);
}
}
private string GetCleanFolderName(string source, string filepath)
{
if (string.IsNullOrWhiteSpace(filepath))
{
return string.Empty;
}
var result = filepath.Substring(source.Length);
if (result.StartsWith("\\"))
{
result = result.Substring(1);
}
result = result.Substring(0, result.Length - new FileInfo(filepath).Name.Length);
return result;
}
Usage:
Zip(#"c:\somefolder\subfolder\source", #"c:\somefolder2\subfolder2\dest");
Or
Zip(#"c:\somefolder\subfolder\source", #"c:\somefolder2\subfolder2\dest\output.zip");
Following code uses a third-party ZIP component from Rebex:
// add content of the local directory C:\Data\
// to the root directory in the ZIP archive
// (ZIP archive C:\archive.zip doesn't have to exist)
Rebex.IO.Compression.ZipArchive.Add(#"C:\archive.zip", #"C:\Data\*", "");
Or if you want to add more folders without need to open and close archive multiple times:
using Rebex.IO.Compression;
...
// open the ZIP archive from an existing file
ZipArchive zip = new ZipArchive(#"C:\archive.zip", ArchiveOpenMode.OpenOrCreate);
// add first folder
zip.Add(#"c:\first\folder\*","\first\folder");
// add second folder
zip.Add(#"c:\second\folder\*","\second\folder");
// close the archive
zip.Close(ArchiveSaveAction.Auto);
You can download the ZIP component here.
Using a free, LGPL licensed SharpZipLib is a common alternative.
Disclaimer: I work for Rebex
"Where should I copy ICSharpCode.SharpZipLib.dll to see that namespace in Visual Studio?"
You need to add the dll file as a reference in your project. Right click on References in the Solution Explorer->Add Reference->Browse and then select the dll.
Finally you'll need to add it as a using statement in whatever files you want to use it in.
ComponentPro ZIP can help you achieve that task. The following code snippet compress files and dirs in a folder. You can use wilcard mask as well.
using ComponentPro.Compression;
using ComponentPro.IO;
...
// Create a new instance.
Zip zip = new Zip();
// Create a new zip file.
zip.Create("test.zip");
zip.Add(#"D:\Temp\Abc"); // Add entire D:\Temp\Abc folder to the archive.
// Add all files and subdirectories from 'c:\test' to the archive.
zip.AddFiles(#"c:\test");
// Add all files and subdirectories from 'c:\my folder' to the archive.
zip.AddFiles(#"c:\my folder", "");
// Add all files and subdirectories from 'c:\my folder' to '22' folder within the archive.
zip.AddFiles(#"c:\my folder2", "22");
// Add all .dat files from 'c:\my folder' to '22' folder within the archive.
zip.AddFiles(#"c:\my folder2", "22", "*.dat");
// Or simply use this to add all .dat files from 'c:\my folder' to '22' folder within the archive.
zip.AddFiles(#"c:\my folder2\*.dat", "22");
// Add *.dat and *.exe files from 'c:\my folder' to '22' folder within the archive.
zip.AddFiles(#"c:\my folder2\*.dat;*.exe", "22");
TransferOptions opt = new TransferOptions();
// Donot add empty directories.
opt.CreateEmptyDirectories = false;
zip.AddFiles(#"c:\abc", "/", opt);
// Close the zip file.
zip.Close();
http://www.componentpro.com/doc/zip has more examples

Problem in using Ionic.Zip namspace

I am using Ionic.zip to zip up the files.
You consider there are 2 files in c:\img\a.txt and b.txt. When zip up these files as following
using (ZipFile zip = new ZipFile())
{
zip.AddItem(#"F:\imp\a.txt");
zip.AddItem(#"F:\imp\b.txt");
zip.AddItem(#"F:\imp\lookup.ini");
zip.AddItem(#"F:\imp\lookups.mdb");
zip.Save("Lookups.zip");
}
It is creating lookups.zip file correctly. But the problem is content of zip file is...
there is one directory named as imp and it is contains those 2files.
But i do not need of the directory entry only i need files which i added.
Please help me.
As shown in the documentation, use the overload which accepts two strings - one for the directory in the zip file:
using (ZipFile zip = new ZipFile())
{
zip.AddItem(#"F:\imp\a.txt", "");
zip.AddItem(#"F:\imp\b.txt", "");
zip.AddItem(#"F:\imp\lookup.ini", "");
zip.AddItem(#"F:\imp\lookups.mdb", "");
zip.Save("Lookups.zip");
}
(That looks like 4 files to me, not 2, and in imp rather than img... but never mind.)

Categories