Whats the best way to zip up files using C#? Ideally I want to be able to seperate files into a single archive.
You can use DotNetZip to archieve this. It´s free to use in any application.
Here´s some sample code:
try
{
// for easy disposal
using (ZipFile zip = new ZipFile())
{
// add this map file into the "images" directory in the zip archive
zip.AddFile("c:\\images\\personal\\7440-N49th.png", "images");
// add the report into a different directory in the archive
zip.AddFile("c:\\Reports\\2008-Regional-Sales-Report.pdf", "files");
zip.AddFile("ReadMe.txt");
zip.Save("MyZipFile.zip");
}
}
catch (System.Exception ex1)
{
System.Console.Error.WriteLine("exception: " + ex1);
}
This is now built into the framework if you have version 4.5+
Otherwise, use Ionic.
Namespace is System.IO.Packaging.ZIPPackage.
See http://visualstudiomagazine.com/articles/2012/05/21/net-framework-gets-zip.aspx for a story.
Have you looked at SharpZipLib?
I believe you can build zip files with classes in the System.IO.Packaging namespace - but every time I've tried to look into it, I've found it rather confusing...
Take a look at this library:
http://www.icsharpcode.net/OpenSource/SharpZipLib/
It is pretty comprehensive, it deals with many formats, is open-source, and you can use in closed-source commercial applications.
It is very simple to use:
byte[] data1 = new byte[...];
byte[] data2 = new byte[...];
/*...*/
var path = #"c:\test.zip";
var zip = new ZipOutputStream(new FileStream(path, FileMode.Create))
{
IsStreamOwner = true
}
zip.PutNextEntry("File1.txt");
zip.Write(data1, 0, data1.Length);
zip.PutNextEntry("File2.txt");
zip.Write(data2, 0, data2.Length);
zip.Close();
zip.Dispose();
There are a few librarys around - the most popular of which are DotNetZip and SharpZipLib.
Hi i created two methods with the ShapLib library (you can download it here http://www.icsharpcode.net/opensource/sharpziplib/) that would like to share, they are very easy to use just pass source and target path (fullpath including folder/file and extension). Hope it help you!
//ALLYOURNAMESPACESHERE
using ...
//SHARPLIB
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
public static class FileUtils
{
/// <summary>
///
/// </summary>
/// <param name="sourcePath"></param>
/// <param name="targetPath"></param>
public static void ZipFile(string sourcePath, string targetPath)
{
string tempZipFilePath = targetPath;
using (FileStream tempFileStream = File.Create(tempZipFilePath, 1024))
{
using (ZipOutputStream zipOutput = new ZipOutputStream(tempFileStream))
{
// Zip with highest compression.
zipOutput.SetLevel(9);
DirectoryInfo directory = new DirectoryInfo(sourcePath);
foreach (System.IO.FileInfo file in directory.GetFiles())
{
// Get local path and create stream to it.
String localFilename = file.FullName;
//ignore directories or folders
//ignore Thumbs.db file since this probably will throw an exception
//another process could be using it. e.g: Explorer.exe windows process
if (!file.Name.Contains("Thumbs") && !Directory.Exists(localFilename))
{
using (FileStream fileStream = new FileStream(localFilename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
// Read full stream to in-memory buffer.
byte[] buffer = new byte[fileStream.Length];
fileStream.Read(buffer, 0, buffer.Length);
// Create a new entry for the current file.
ZipEntry entry = new ZipEntry(file.Name);
entry.DateTime = DateTime.Now;
// set Size and the crc, because the information
// about the size and crc should be stored in the header
// if it is not set it is automatically written in the footer.
// (in this case size == crc == -1 in the header)
// Some ZIP programs have problems with zip files that don't store
// the size and crc in the header.
entry.Size = fileStream.Length;
fileStream.Close();
// Update entry and write to zip stream.
zipOutput.PutNextEntry(entry);
zipOutput.Write(buffer, 0, buffer.Length);
// Get rid of the buffer, because this
// is a huge impact on the memory usage.
buffer = null;
}
}
}
// Finalize the zip output.
zipOutput.Finish();
// Flushes the create and close.
zipOutput.Flush();
zipOutput.Close();
}
}
}
public static void unZipFile(string sourcePath, string targetPath)
{
if (!Directory.Exists(targetPath))
Directory.CreateDirectory(targetPath);
using (ZipInputStream s = new ZipInputStream(File.OpenRead(sourcePath)))
{
ZipEntry theEntry;
while ((theEntry = s.GetNextEntry()) != null)
{
if (theEntry.Name != String.Empty)
{
using (FileStream streamWriter = File.Create(targetPath + "\\" + theEntry.Name))
{
int size = 2048;
byte[] data = new byte[2048];
while (true)
{
size = s.Read(data, 0, data.Length);
if (size > 0)
{
streamWriter.Write(data, 0, size);
}
else
{
break;
}
}
}
}
}
}
}
}
Related
I wrote a program that unzip a file (.zip) using SharpZipLib...
The following code:
public void UnZip(string zipFilePath, string extractionPath)
{
FastZip fz = new FastZip();
fz.ExtractZip(zipFilePath, extractionPath, null);
}
I get the following Exception:
Additional information: The access to the path "C:\Program files (x86)\... Thumbs.db" was refused.
The program starts with Admin rights and the file "Thumbs.db" does not exist in the .zip archive.
Who knows further?
Greets and thanks!
I would ignore the "Thumbs.db" file as its an OS file.
Maybe something like this:
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;
public void ExtractZipFile(string archiveFilenameIn, string password, string outFolder) {
ZipFile zf = null;
try {
FileStream fs = File.OpenRead(archiveFilenameIn);
zf = new ZipFile(fs);
if (!String.IsNullOrEmpty(password)) {
zf.Password = password; // AES encrypted entries are handled automatically
}
foreach (ZipEntry zipEntry in zf) {
if (!zipEntry.IsFile) {
continue; // Ignore directories
}
String entryFileName = zipEntry.Name;
// to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName);
// Optionally match entrynames against a selection list here to skip as desired.
// The unpacked length is available in the zipEntry.Size property.
byte[] buffer = new byte[4096]; // 4K is optimum
Stream zipStream = zf.GetInputStream(zipEntry);
// Manipulate the output filename here as desired.
String fullZipToPath = Path.Combine(outFolder, entryFileName);
string directoryName = Path.GetDirectoryName(fullZipToPath);
if (directoryName.Length > 0)
Directory.CreateDirectory(directoryName);
// Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size
// of the file, but does not waste memory.
// The "using" will close the stream even if an exception occurs.
using (FileStream streamWriter = File.Create(fullZipToPath)) {
StreamUtils.Copy(zipStream, streamWriter, buffer);
}
}
} finally {
if (zf != null) {
zf.IsStreamOwner = true; // Makes close also shut the underlying stream
zf.Close(); // Ensure we release resources
}
}
}
I need to get the number of entries and original file size of each entry in a ZIP file. On .NET 4.5, we can use the C# classes ZipArchive and ZipFile as shown below, but these classes are not available in .NET 2.0. What are my options then?
using (ZipArchive archive = ZipFile.OpenRead(fileName))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
Console.WriteLine("[INFO] Zip entry {0} original file size: [{1}]", entry.name, entry.Length);
}
}
Thanks in advance.
Using [ICsharpZipLib] (https://icsharpcode.github.io/SharpZipLib/)
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;
public void ExtractZipFile(string archiveFilenameIn, string password, string outFolder) {
ZipFile zf = null;
try {
FileStream fs = File.OpenRead(archiveFilenameIn);
zf = new ZipFile(fs);
if (!String.IsNullOrEmpty(password)) {
zf.Password = password; // AES encrypted entries are handled automatically
}
foreach (ZipEntry zipEntry in zf) {
if (!zipEntry.IsFile) {
continue; // Ignore directories
}
String entryFileName = zipEntry.Name;
// to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName);
// Optionally match entrynames against a selection list here to skip as desired.
// The unpacked length is available in the zipEntry.Size property.
byte[] buffer = new byte[4096]; // 4K is optimum
Stream zipStream = zf.GetInputStream(zipEntry);
// Manipulate the output filename here as desired.
String fullZipToPath = Path.Combine(outFolder, entryFileName);
string directoryName = Path.GetDirectoryName(fullZipToPath);
if (directoryName.Length > 0)
Directory.CreateDirectory(directoryName);
// Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size
// of the file, but does not waste memory.
// The "using" will close the stream even if an exception occurs.
using (FileStream streamWriter = File.Create(fullZipToPath)) {
StreamUtils.Copy(zipStream, streamWriter, buffer);
}
}
} finally {
if (zf != null) {
zf.IsStreamOwner = true; // Makes close also shut the underlying stream
zf.Close(); // Ensure we release resources
}
}
}
I have files (from 3rd parties) that are being FTP'd to a directory on our server. I download them and process them even 'x' minutes. Works great.
Now, some of the files are .zip files. Which means I can't process them. I need to unzip them first.
FTP has no concept of zip/unzipping - so I'll need to grab the zip file, unzip it, then process it.
Looking at the MSDN zip api, there seems to be no way i can unzip to a memory stream?
So is the only way to do this...
Unzip to a file (what directory? need some -very- temp location ...)
Read the file contents
Delete file.
NOTE: The contents of the file are small - say 4k <-> 1000k.
Zip compression support is built in:
using System.IO;
using System.IO.Compression;
// ^^^ requires a reference to System.IO.Compression.dll
static class Program
{
const string path = ...
static void Main()
{
using(var file = File.OpenRead(path))
using(var zip = new ZipArchive(file, ZipArchiveMode.Read))
{
foreach(var entry in zip.Entries)
{
using(var stream = entry.Open())
{
// do whatever we want with stream
// ...
}
}
}
}
}
Normally you should avoid copying it into another stream - just use it "as is", however, if you absolutely need it in a MemoryStream, you could do:
using(var ms = new MemoryStream())
{
stream.CopyTo(ms);
ms.Position = 0; // rewind
// do something with ms
}
You can use ZipArchiveEntry.Open to get a stream.
This code assumes the zip archive has one text file.
using (FileStream fs = new FileStream(path, FileMode.Open))
using (ZipArchive zip = new ZipArchive(fs) )
{
var entry = zip.Entries.First();
using (StreamReader sr = new StreamReader(entry.Open()))
{
Console.WriteLine(sr.ReadToEnd());
}
}
using (ZipArchive archive = new ZipArchive(webResponse.GetResponseStream()))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
Stream s = entry.Open();
var sr = new StreamReader(s);
var myStr = sr.ReadToEnd();
}
}
Looks like here is what you need:
using (var za = ZipFile.OpenRead(path))
{
foreach (var entry in za.Entries)
{
using (var r = new StreamReader(entry.Open()))
{
//your code here
}
}
}
You can use SharpZipLib among a variety of other libraries to achieve this.
You can use the following code example to unzip to a MemoryStream, as shown on their wiki:
using ICSharpCode.SharpZipLib.Zip;
// Compresses the supplied memory stream, naming it as zipEntryName, into a zip,
// which is returned as a memory stream or a byte array.
//
public MemoryStream CreateToMemoryStream(MemoryStream memStreamIn, string zipEntryName) {
MemoryStream outputMemStream = new MemoryStream();
ZipOutputStream zipStream = new ZipOutputStream(outputMemStream);
zipStream.SetLevel(3); //0-9, 9 being the highest level of compression
ZipEntry newEntry = new ZipEntry(zipEntryName);
newEntry.DateTime = DateTime.Now;
zipStream.PutNextEntry(newEntry);
StreamUtils.Copy(memStreamIn, zipStream, new byte[4096]);
zipStream.CloseEntry();
zipStream.IsStreamOwner = false; // False stops the Close also Closing the underlying stream.
zipStream.Close(); // Must finish the ZipOutputStream before using outputMemStream.
outputMemStream.Position = 0;
return outputMemStream;
// Alternative outputs:
// ToArray is the cleaner and easiest to use correctly with the penalty of duplicating allocated memory.
byte[] byteArrayOut = outputMemStream.ToArray();
// GetBuffer returns a raw buffer raw and so you need to account for the true length yourself.
byte[] byteArrayOut = outputMemStream.GetBuffer();
long len = outputMemStream.Length;
}
Ok so combining all of the above, suppose you want to in a very simple way take a zip file called
"file.zip" and extract it to "C:\temp" folder. (Note: This example was only tested for compress text files) You may need to do some modifications for binary files.
using System.IO;
using System.IO.Compression;
static void Main(string[] args)
{
//Call it like this:
Unzip("file.zip",#"C:\temp");
}
static void Unzip(string sourceZip, string targetPath)
{
using (var z = ZipFile.OpenRead(sourceZip))
{
foreach (var entry in z.Entries)
{
using (var r = new StreamReader(entry.Open()))
{
string uncompressedFile = Path.Combine(targetPath, entry.Name);
File.WriteAllText(uncompressedFile,r.ReadToEnd());
}
}
}
}
Inside my app, I am trying to download about 180 small audio files all at once. I tried the BackgroundTransferService, but it does not seem stable with so many small files. So, now I am downloading a ZIP of all those audio and want extract them in "audio" folder. I tried the method in this thread:
How to unzip files in Windows Phone 8
But I get this error: 'System.IO.IOException' occurred in mscorlib.ni.dll... in the following code. How can I overcome this issue?
while (reader.ReadInt32() != 101010256)
{
reader.BaseStream.Seek(-5, SeekOrigin.Current); // this line causes error
}...
Also, where do I need to place this code and where do I give it the destination directory?
IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
using (IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile(#"audio.rar", FileMode.Open, FileAccess.ReadWrite))
{
UnZipper unzip = new UnZipper(fileStream);
foreach (string filename in unzip.FileNamesInZip())
{
string FileName = filename;
}
}
Use Silverlight SharpZipLib. Add SharpZipLib.WindowsPhone7.dll to your project (works on WP8 silverlight also).
private void Unzip()
{
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
{
ZipEntry entry;
int size;
byte[] data = new byte[2048];
using (ZipInputStream zip = new ZipInputStream(store.OpenFile("YourZipFile.zip", FileMode.Open)))
{
// retrieve each file/folder
while ((entry = zip.GetNextEntry()) != null)
{
if (!entry.IsFile)
continue;
// if file name is music/rock/new.mp3, we need only new.mp3
// also you must make sure file name doesn't have unsupported chars like /,\,etc.
int index = entry.Name.LastIndexOf('/');
string name = entry.Name.Substring(index + 1);
// create file in isolated storage
using (var writer = store.OpenFile(name, FileMode.Create))
{
while (true)
{
size = zip.Read(data, 0, data.Length);
if (size > 0)
writer.Write(data, 0, size);
else
break;
}
}
}
}
}
}
There are several 3rd party libraries in order to extract ZIP files in WP8 like the ZipLib which you can download from # http://slsharpziplib.codeplex.com/
however DotNetZip a parent ZipLib and much more stable.
Here is a sample code. Not checked if it works, but this is how you go at it.
ZipFile zip = ZipFile.Read(ZipFileToUnzip);
foreach (ZipEntry ent in zip)
{
ent.Extract(DirectoryWhereToUnizp, ExtractExistingFileAction.OverwriteSilently);
}
I have just solved this. what you can do is use this method and your file will go save to isolated storage in proper folder structure as present in your zip file. you can change according to your need where you want to store the data.
I have just read a sample.zip file. From your app folder.
private async Task UnZipFile()
{
var myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
using (var fileStream = Application.GetResourceStream(new Uri("sample.zip", UriKind.Relative)).Stream)
{
var unzip = new UnZipper(fileStream);
foreach (string filename in unzip.FileNamesInZip)
{
if (!string.IsNullOrEmpty(filename))
{
if (filename.Any(m => m.Equals('/')))
{
myIsolatedStorage.CreateDirectory(filename.Substring(0, filename.LastIndexOfAny(new char[] { '/' })));
}
//save file entry to storage
using (var streamWriter =
new StreamWriter(new IsolatedStorageFileStream(filename,
FileMode.Create,
FileAccess.ReadWrite,
myIsolatedStorage)))
{
streamWriter.Write(unzip.GetFileStream(filename));
}
}
}
}
}
cheers :)
I'm working in C#, and I'm downloading for the internet a zip file with one XML file in it. and I wish to load this XML file. This is what I have so far:
byte[] data;
WebClient webClient = new WebClient();
try {
data = webClient.DownloadData(downloadUrl);
}
catch (Exception ex) {
Console.WriteLine("Error in DownloadData (Ex:{0})", ex.Message);
throw;
}
if (data == null) {
Console.WriteLine("Bulk data is null");
throw new Exception("Bulk data is null");
}
//Create the stream
MemoryStream stream = new MemoryStream(data);
XmlDocument document = new XmlDocument();
//Gzip
GZipStream gzipStream = new GZipStream(stream, CompressionMode.Decompress);
//Load report straight from the gzip stream
try {
document.Load(gzipStream);
}
catch (Exception ex) {
Console.WriteLine("Error in Load (Ex:{0})", ex.Message);
throw;
}
in document.Load I'm always getting the following exception:
The magic number in GZip header is not correct. Make sure you are passing in a GZip stream.
What I'm doing wrong?
Apparently SharpZipLib is now unmaintained and you probably want to avoid it:
https://stackoverflow.com/a/593030
In .NET 4.5 there is now built in support for zip files, so for your example it would be:
var data = new WebClient().DownloadData(downloadUrl);
//Create the stream
var stream = new MemoryStream(data);
var document = new XmlDocument();
//zip
var zipArchive = new ZipArchive(stream);
//Load report straight from the zip stream
document.Load(zipArchive.Entries[0].Open());
If you have a byte array that contains a zip archive with a single file, you can use the ZipArchive class to get an unzipped byte array with the file's data.
ZipArchive is contained in .NET 4.5, in the assembly System.IO.Compression.FileSystem (you need to reference it explicitly).
The following function, adapted from this answer, works for me:
public static byte[] UnzipSingleEntry(byte[] zipped)
{
using (var memoryStream = new MemoryStream(zipped))
{
using (var archive = new ZipArchive(memoryStream))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
using (var entryStream = entry.Open())
{
using (var reader = new BinaryReader(entryStream))
{
return reader.ReadBytes((int)entry.Length);
}
}
}
}
}
return null; // To quiet my compiler
}
I am using SharpZipLib and it's working great !
Below is a function that encapsulate the library
public static void Compress(FileInfo sourceFile, string destinationFileName,string destinationTempFileName)
{
Crc32 crc = new Crc32();
string zipFile = Path.Combine(sourceFile.Directory.FullName, destinationTempFileName);
zipFile = Path.ChangeExtension(zipFile, ZIP_EXTENSION);
using (FileStream fs = File.Create(zipFile))
{
using (ZipOutputStream zOut = new ZipOutputStream(fs))
{
zOut.SetLevel(9);
ZipEntry entry = new ZipEntry(ZipEntry.CleanName(destinationFileName));
entry.DateTime = DateTime.Now;
entry.ZipFileIndex = 1;
entry.Size = sourceFile.Length;
using (FileStream sourceStream = sourceFile.OpenRead())
{
crc.Reset();
long len = sourceFile.Length;
byte[] buffer = new byte[bufferSize];
while (len > 0)
{
int readSoFar = sourceStream.Read(buffer, 0, buffer.Length);
crc.Update(buffer, 0, readSoFar);
len -= readSoFar;
}
entry.Crc = crc.Value;
zOut.PutNextEntry(entry);
len = sourceStream.Length;
sourceStream.Seek(0, SeekOrigin.Begin);
while (len > 0)
{
int readSoFar = sourceStream.Read(buffer, 0, buffer.Length);
zOut.Write(buffer, 0, readSoFar);
len -= readSoFar;
}
}
zOut.Finish();
zOut.Close();
}
fs.Close();
}
}
As the others have mentioned GZip and Zip are not the same so you might need to use a zip library. I use a library called: DotNetZip - available from the below site:
http://dotnetzip.codeplex.com/
From GZipStream Class description:
Compressed GZipStream objects written to a file with an extension of .gz can be decompressed using many common compression tools; however, this class does not inherently provide functionality for adding files to or extracting files from .zip archives
So unless you control server-side files, I'd suggest looking for specific zip-targeted library (SharpZipLib for example).