How to zip multiple files using only .net api in c# - c#

I like to zip multiple files which are being created dynamically in my web application. Those files should be zipped. For this, i dont want to use any third-party tools. just like to use .net api in c#

With the release of the .NET Framework 4.5 this is actually a lot easier now with the updates to System.IO.Compression which adds the ZipFile class. There is a good walk-through on codeguru; however, the basics are in line with the following example:
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.IO.Compression.FileSystem;
namespace ZipFileCreator
{
public static class ZipFileCreator
{
/// <summary>
/// Create a ZIP file of the files provided.
/// </summary>
/// <param name="fileName">The full path and name to store the ZIP file at.</param>
/// <param name="files">The list of files to be added.</param>
public static void CreateZipFile(string fileName, IEnumerable<string> files)
{
// Create and open a new ZIP file
var zip = ZipFile.Open(fileName, ZipArchiveMode.Create);
foreach (var file in files)
{
// Add the entry for each file
zip.CreateEntryFromFile(file, Path.GetFileName(file), CompressionLevel.Optimal);
}
// Dispose of the object when we are done
zip.Dispose();
}
}
}

Use System.IO.Packaging in .NET 3.0+.
See this introduction to System.IO.Packaging
If you're able to take a .NET 4.5 dependency, there's a System.IO.Compression.ZipArchive in that universe; see walkthrough article here (via InfoQ news summary article here)

Simple zip file with flat structure:
using System.IO;
using System.IO.Compression;
private static void CreateZipFile(IEnumerable<FileInfo> files, string archiveName)
{
using (var stream = File.OpenWrite(archiveName))
using (ZipArchive archive = new ZipArchive(stream, System.IO.Compression.ZipArchiveMode.Create))
{
foreach (var item in files)
{
archive.CreateEntryFromFile(item.FullName, item.Name, CompressionLevel.Optimal);
}
}
}
You need to add reference to System.IO.Compression and System.IO.Compression.FileSystem

I'm not sure what you mean by not wanting to use thrid party tools, but I assume its that you don't want some nasty interop to programmatically do it through another piece of software.
I recommend using ICSharpCode SharpZipLib
This can be added to your project as a reference DLL and is fairly straightforward for creating ZIP files and reading them.

Well you can zip the files using following function you have to just pass the file bytes and this function will zip the file bytes passed as parameter and return the zipped file bytes.
public static byte[] PackageDocsAsZip(byte[] fileBytesTobeZipped, string packageFileName)
{
try
{
string parentSourceLoc2Zip = #"C:\UploadedDocs\SG-ACA OCI Packages";
if (Directory.Exists(parentSourceLoc2Zip) == false)
{
Directory.CreateDirectory(parentSourceLoc2Zip);
}
//if destination folder already exists then delete it
string sourceLoc2Zip = string.Format(#"{0}\{1}", parentSourceLoc2Zip, packageFileName);
if (Directory.Exists(sourceLoc2Zip) == true)
{
Directory.Delete(sourceLoc2Zip, true);
}
Directory.CreateDirectory(sourceLoc2Zip);
FilePath = string.Format(#"{0}\{1}",
sourceLoc2Zip,
"filename.extension");//e-g report.xlsx , report.docx according to exported file
File.WriteAllBytes(FilePath, fileBytesTobeZipped);
//if zip already exists then delete it
if (File.Exists(sourceLoc2Zip + ".zip"))
{
File.Delete(sourceLoc2Zip + ".zip");
}
//now zip the source location
ZipFile.CreateFromDirectory(sourceLoc2Zip, sourceLoc2Zip + ".zip", System.IO.Compression.CompressionLevel.Optimal, true);
return File.ReadAllBytes(sourceLoc2Zip + ".zip");
}
catch
{
throw;
}
}
Now if you want to export this zip bytes created for user to download you can call this function using following lines
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=Report.zip");
Response.ContentType = "application/zip";
Response.BinaryWrite(PackageDocsAsZip(fileBytesToBeExported ,"TemporaryFolderName"));
Response.End();

You could always call a third-party executable like 7-zip with an appropriate command line using the System.Diagnostics.Process class. There's no interop that way because you're just asking the OS to launch a binary.

DotNetZip is the way to go (dotnetzip.codeplex.com)... don't try the .NET Packaging library.. too hard to use and the [Content_Types].xml that it puts in there bothers me..

Check out System.IO.Compression.DeflateStream. The linked documentation page also offers an example.

Related

Compressing a folder to gzip/zip file from PCL

I am developing UWP and Windows phone 8.1 in the same solution.
On both projects I need a functionality of compressing a whole folder to one gzip file (in order to send it to server).
Libraries I've tried and encountered issues with:
SharpZipLib - uses System.IClonable which I cannot referance in my PCL project
DotNetZip - Not Suporting PCL/UWP
System.IO.Compression - Work only with Stream, cannot compress whole folder
I can split the implementation for each platform (although it is not perfect) but I still didn't found something that can be used in UWP.
Any help will be appriciated
Ok, so I found this project called SharpZipLib.Portable which is also an open source
Github : https://github.com/ygrenier/SharpZipLib.Portable
Really nice :)
Working on a UWP library you will have to use the Stream subsystem of the System.IO.Compression. There are many such limitations when you need a PCL version of .NET Framework. Live with that.
In your context that is not much of a trouble.
The required usings are:
using System;
using System.IO;
using System.IO.Compression;
Then the methods...
private void CreateArchive(string iArchiveRoot)
{
using (MemoryStream outputStream = new MemoryStream())
{
using (ZipArchive archive = new ZipArchive(outputStream, ZipArchiveMode.Create, true))
{
//Pick all the files you need in the archive.
string[] files = Directory.GetFiles(iArchiveRoot, "*", SearchOption.AllDirectories);
foreach (string filePath in files)
{
FileAppend(iArchiveRoot, filePath, archive);
}
}
}
}
private void FileAppend(
string iArchiveRootPath,
string iFileAbsolutePath,
ZipArchive iArchive)
{
//Has to return something like "dir1/dir2/part1.txt".
string fileRelativePath = MakeRelativePath(iFileAbsolutePath, iArchiveRootPath);
ZipArchiveEntry clsEntry = iArchive.CreateEntry(fileRelativePath, CompressionLevel.Optimal);
Stream entryData = clsEntry.Open();
//Write the file data to the ZipArchiveEntry.
entryData.Write(...);
}
//http://stackoverflow.com/questions/275689/how-to-get-relative-path-from-absolute-path
private string MakeRelativePath(
string fromPath,
string toPath)
{
if (String.IsNullOrEmpty(fromPath)) throw new ArgumentNullException("fromPath");
if (String.IsNullOrEmpty(toPath)) throw new ArgumentNullException("toPath");
Uri fromUri = new Uri(fromPath);
Uri toUri = new Uri(toPath);
if (fromUri.Scheme != toUri.Scheme) { return toPath; } // path can't be made relative.
Uri relativeUri = fromUri.MakeRelativeUri(toUri);
String relativePath = Uri.UnescapeDataString(relativeUri.ToString());
if (toUri.Scheme.Equals("file", StringComparison.OrdinalIgnoreCase))
{
relativePath = relativePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
}
return relativePath;
}

Restrict users to upload zip file with folder inside

I have a file upload control.
I restrict users to upload only zip files.
the namespace i use is Ionic.Zip;
I also want check if that zip file has a folder inside.
I have to restrict the users not upload a zipfile with a folder inside.
I could check how many files inside zip file like
using (ZipFile zip = ZipFile.Read(file_path))
{
if (zip.Count < 5)
{
}
I do not know how to check for a folder inside
Anyone can help me please.
thanks in advance
void Main()
{
var isGood=false;
using (ZipFile zip = new ZipFile(#"c:\\1.zip"))
{
for (var i=0;i<zip.Count;i++)
if (zip[i].Attributes==FileAttributes.Directory)
{
isGood=false;
break;
}
}
if (isGood) Console.WriteLine ("ok");
else
Console.WriteLine ("error");
}
// Define other methods and classes here
edit :
there's seems to be a problem with the way you created this zip file.
I extracted the files from the file you sent me and created new zip : (named 3.zip):
and as you can see - the code works :
so I guess the dll is not powerful enough to recognize edge format
You can iterate on your zip object's ZipEntries - ZipEntry object contains IsDirectory property.
foreach(var entry in zip)
{
if(entry.IsDirectory)
{
//your stuff
}
}

Save all the folder structure with DotNetZip

I did this simple code with the latest version of the library DotNetZip, for some reason when I add a file I get all the folder structure. For example if I add:
C:\one folder\two folders\File.doc
Inside the zip file I will have
one folder\two folders\File.doc
But my expected result would be to have just the file.doc
This is my code, I don't know if I am doing something wrong or what..:
//C#
public static void MethodOne(string PathInput, int LimitKb=0, bool DeleteInput=false)
{
using (ZipFile zip = new ZipFile())
{
//add file to zip
zip.AddFile(PathInput);
//save it
zip.Save(PathInput + ".zip");
}
}
Thanks! :)
Use the overloaded, two-parameter call to AddFile where you specify the internal directory structure.
zip.AddFile(filename, String.Empty);
I think that would do what you want but I can't easily test it.

DotNetZip - How to extract to working directory

I am trying to get a method that uses the DotNetZip library to extract a file to the current working directory, although I can't seem to get it to do it, it wants a file path:
private void unzipfiles()
{
using (var zip = Ionic.Zip.ZipFile.Read("ccsetup307.zip"))
{
zip.ExtractAll("directory-name",ExtractExistingFileAction.OverwriteSilently);
}
}
If you want to extract to the current directory, why don't you use the GetCurrentDirectory method and pass that in as the expected parameter like so:
using (var zip = Ionic.Zip.ZipFile.Read("ccsetup307.zip"))
{
zip.ExtractAll(Directory.GetCurrentDirectory()
,ExtractExistingFileAction.OverwriteSilently);
}
http://msdn.microsoft.com/en-us/library/system.io.directory.getcurrentdirectory.aspx
I know it isn't implicit but it should work fine for you.
You can use the below code as well.
string x = "your file name";
using (ZipFile zip = ZipFile.Read(x))
{
zip.ExtractAll(Path.GetDirectoryName(x), ExtractExistingFileAction.OverwriteSilently);
}

How can I list the contents of a .zip folder in c#?

How can I list the contents of a zipped folder in C#? For example how to know how many items are contained within a zipped folder, and what is their name?
.NET 4.5 or newer finally has built-in capability to handle generic zip files with the System.IO.Compression.ZipArchive class (http://msdn.microsoft.com/en-us/library/system.io.compression.ziparchive%28v=vs.110%29.aspx) in assembly System.IO.Compression. No need for any 3rd party library.
string zipPath = #"c:\example\start.zip";
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
Console.WriteLine(entry.FullName);
}
}
DotNetZip - Zip file manipulation in .NET languages
DotNetZip is a small, easy-to-use class library for manipulating .zip files. It can enable .NET applications written in VB.NET, C#, any .NET language, to easily create, read, and update zip files.
sample code to read a zip:
using (var zip = ZipFile.Read(PathToZipFolder))
{
int totalEntries = zip.Entries.Count;
foreach (ZipEntry e in zip.Entries)
{
e.FileName ...
e.CompressedSize ...
e.LastModified...
}
}
If you are using .Net Framework 3.0 or later, check out the System.IO.Packaging Namespace. This will remove your dependancy on an external library.
Specifically check out the ZipPackage Class.
Check into SharpZipLib
ZipInputStream inStream = new ZipInputStream(File.OpenRead(fileName));
while (inStream.GetNextEntry())
{
ZipEntry entry = inStream.GetNextEntry();
//write out your entry's filename
}
Ick - that code using the J# runtime is hideous! And I don't agree that it is the best way - J# is out of support now. And it is a HUGE runtime, if all you want is ZIP support.
How about this - it uses DotNetZip (Free, MS-Public license)
using (ZipFile zip = ZipFile.Read(zipfile) )
{
bool header = true;
foreach (ZipEntry e in zip)
{
if (header)
{
System.Console.WriteLine("Zipfile: {0}", zip.Name);
if ((zip.Comment != null) && (zip.Comment != ""))
System.Console.WriteLine("Comment: {0}", zip.Comment);
System.Console.WriteLine("\n{1,-22} {2,9} {3,5} {4,9} {5,3} {6,8} {0}",
"Filename", "Modified", "Size", "Ratio", "Packed", "pw?", "CRC");
System.Console.WriteLine(new System.String('-', 80));
header = false;
}
System.Console.WriteLine("{1,-22} {2,9} {3,5:F0}% {4,9} {5,3} {6:X8} {0}",
e.FileName,
e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"),
e.UncompressedSize,
e.CompressionRatio,
e.CompressedSize,
(e.UsesEncryption) ? "Y" : "N",
e.Crc32);
if ((e.Comment != null) && (e.Comment != ""))
System.Console.WriteLine(" Comment: {0}", e.Comment);
}
}
I'm relatively new here so maybe I'm not understanding what's going on. :-)
There are currently 4 answers on this thread where the two best answers have been voted down. (Pearcewg's and cxfx's) The article pointed to by pearcewg is important because it clarifies some licensing issues with SharpZipLib.
We recently evaluated several .Net compression libraries, and found that DotNetZip is currently the best aleternative.
Very short summary:
System.IO.Packaging is significantly slower than DotNetZip.
SharpZipLib is GPL - see article.
So for starters, I voted those two answers up.
Kim.
If you are like me and do not want to use an external component, here is some code I developed last night using .NET's ZipPackage class.
var zipFilePath = "c:\\myfile.zip";
var tempFolderPath = "c:\\unzipped";
using (Package package = ZipPackage.Open(zipFilePath, FileMode.Open, FileAccess.Read))
{
foreach (PackagePart part in package.GetParts())
{
var target = Path.GetFullPath(Path.Combine(tempFolderPath, part.Uri.OriginalString.TrimStart('/')));
var targetDir = target.Remove(target.LastIndexOf('\\'));
if (!Directory.Exists(targetDir))
Directory.CreateDirectory(targetDir);
using (Stream source = part.GetStream(FileMode.Open, FileAccess.Read))
{
source.CopyTo(File.OpenWrite(target));
}
}
}
Things to note:
The ZIP archive MUST have a [Content_Types].xml file in its root. This was a non-issue for my requirements as I will control the zipping of any ZIP files that get extracted through this code. For more information on the [Content_Types].xml file, please refer to: A New Standard For Packaging Your Data There is an example file below Figure 13 of the article.
This code uses the Stream.CopyTo method in .NET 4.0
The best way is to use the .NET built in J# zip functionality, as shown in MSDN: http://msdn.microsoft.com/en-us/magazine/cc164129.aspx. In this link there is a complete working example of an application reading and writing to zip files. For the concrete example of listing the contents of a zip file (in this case a Silverlight .xap application package), the code could look like this:
ZipFile package = new ZipFile(packagePath);
java.util.Enumeration entries = package.entries();
//We have to use Java enumerators because we
//use java.util.zip for reading the .zip files
while ( entries.hasMoreElements() )
{
ZipEntry entry = (ZipEntry) entries.nextElement();
if (!entry.isDirectory())
{
string name = entry.getName();
Console.WriteLine("File: " + name + ", size: " + entry.getSize() + ", compressed size: " + entry.getCompressedSize());
}
else
{
// Handle directories...
}
}
Aydsman had a right pointer, but there are problems. Specifically, you might find issues opening zip files, but is a valid solution if you intend to only create pacakges. ZipPackage implements the abstract Package class and allows manipulation of zip files. There is a sample of how to do it in MSDN: http://msdn.microsoft.com/en-us/library/ms771414.aspx. Roughly the code would look like this:
string packageRelationshipType = #"http://schemas.microsoft.com/opc/2006/sample/document";
string resourceRelationshipType = #"http://schemas.microsoft.com/opc/2006/sample/required-resource";
// Open the Package.
// ('using' statement insures that 'package' is
// closed and disposed when it goes out of scope.)
foreach (string packagePath in downloadedFiles)
{
Logger.Warning("Analyzing " + packagePath);
using (Package package = Package.Open(packagePath, FileMode.Open, FileAccess.Read))
{
Logger.OutPut("package opened");
PackagePart documentPart = null;
PackagePart resourcePart = null;
// Get the Package Relationships and look for
// the Document part based on the RelationshipType
Uri uriDocumentTarget = null;
foreach (PackageRelationship relationship in
package.GetRelationshipsByType(packageRelationshipType))
{
// Resolve the Relationship Target Uri
// so the Document Part can be retrieved.
uriDocumentTarget = PackUriHelper.ResolvePartUri(
new Uri("/", UriKind.Relative), relationship.TargetUri);
// Open the Document Part, write the contents to a file.
documentPart = package.GetPart(uriDocumentTarget);
//ExtractPart(documentPart, targetDirectory);
string stringPart = documentPart.Uri.ToString().TrimStart('/');
Logger.OutPut(" Got: " + stringPart);
}
// Get the Document part's Relationships,
// and look for required resources.
Uri uriResourceTarget = null;
foreach (PackageRelationship relationship in
documentPart.GetRelationshipsByType(
resourceRelationshipType))
{
// Resolve the Relationship Target Uri
// so the Resource Part can be retrieved.
uriResourceTarget = PackUriHelper.ResolvePartUri(
documentPart.Uri, relationship.TargetUri);
// Open the Resource Part and write the contents to a file.
resourcePart = package.GetPart(uriResourceTarget);
//ExtractPart(resourcePart, targetDirectory);
string stringPart = resourcePart.Uri.ToString().TrimStart('/');
Logger.OutPut(" Got: " + stringPart);
}
}
}
The best way seems to use J#, as shown in MSDN: http://msdn.microsoft.com/en-us/magazine/cc164129.aspx
There are pointers to more c# .zip libraries with different licenses, like SharpNetZip and DotNetZip in this article: how to read files from uncompressed zip in c#?. They might be unsuitable because of the license requirements.

Categories