using System;
using System.Collections.Generic;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;
namespace DelftTools.Utils.IO
{
public static class ZipFileUtils
{
//todo add callback function to report when extraction is finished. use separate thread?
public static void Extract(string zipFile, string destinationPath)
{
var fastZip=new FastZip();
fastZip.ExtractZip(zipFile,destinationPath,"");
}
///
/// Creates a zip file containing the provided filePaths. (File will be overwritten when it already exits)
///
/// Name and path of the zipfile to create
/// List with files to add to the zip file
/// Throws IOExecptions
public static void Create(string zipFileName, List filePaths)
{
Create(zipFileName, filePaths, true);
}
///
/// Creates a zip file containing the provided filePaths. (File will be overwritten when it already exits)
/// The zip entries will be stored relative if dirContainingZipFiles is specified, and absolute otherwise.
///
/// Name and path of the zipfile to create
/// The directory that containings the files to be zipped (absolute path)
/// List with files to add to the zip file
/// Throws IOExecptions
public static void Create(string zipFileName, string dirContainingZipFiles, List filePaths)
{
Create(zipFileName, dirContainingZipFiles, filePaths, true);
}
///
/// Creates a zip file containing the provided filePaths.
///
/// Name and path of the zipfile to create
/// List with files to add to the zip file
/// Determents if the file will be overwritten if it already exists
/// Throws IOExecptions
public static void Create(string zipFileName, List filePaths, bool overwriteIfExits)
{
Create(zipFileName, null, filePaths, overwriteIfExits);
}
///
/// Creates a zip file containing the provided filePaths. The zip entries will be stored relative if dirContainingZipFiles
/// is specified, and absolute otherwise.
///
/// Name and path of the zipfile to create
/// The directory that containings the files to be zipped (absolute path)
/// List with files to add to the zip file
/// Determents if the file will be overwritten if it already exists
/// Optinal: set of files that should be named different in the zip file (only works for non-absolute paths)
/// Throws IOExecptions
public static void Create(string zipFileName, string dirContainingZipFiles, List filePaths, bool overwriteIfExits, IDictionary fileNamesInZipFile = null)
{
if (!overwriteIfExits && File.Exists(zipFileName))
{
throw new IOException("File already exists.");
}
ZipOutputStream zipStream = null;
try
{
FileStream fsOut = File.Create(zipFileName);
zipStream = new ZipOutputStream(fsOut);
if (filePaths != null)
{
foreach (var incomingFilePath in filePaths)
{
string actualFilePath = incomingFilePath;
string filePathInZipFileKey = incomingFilePath;
string filePathInZipFile = incomingFilePath;
if (dirContainingZipFiles != null)
{
if (Path.IsPathRooted(incomingFilePath))
{
filePathInZipFileKey = FileUtils.GetRelativePath(dirContainingZipFiles, incomingFilePath);
}
else
{
actualFilePath = Path.Combine(dirContainingZipFiles, incomingFilePath);
}
}
if (fileNamesInZipFile != null && fileNamesInZipFile.ContainsKey(filePathInZipFileKey))
{
filePathInZipFile = fileNamesInZipFile[filePathInZipFileKey];
}
if (Path.IsPathRooted(filePathInZipFile))
{
throw new InvalidOperationException("");
}
FileInfo fi = new FileInfo(actualFilePath);
string entryName = ZipEntry.CleanName(filePathInZipFile); // Removes drive from name and fixes slash direction;
ZipEntry newEntry = new ZipEntry(entryName);
newEntry.DateTime = fi.LastWriteTime; // Note the zip format stores 2 second granularity
newEntry.Size = fi.Length;
zipStream.PutNextEntry(newEntry);
// Zip the file in buffered chunks
// the "using" will close the stream even if an exception occurs
byte[] buffer = new byte[4096];
using (FileStream streamReader = File.OpenRead(actualFilePath))
{
StreamUtilsCopy(streamReader, zipStream, buffer);
}
zipStream.CloseEntry();
}
}
}
finally
{
if (zipStream != null)
{
zipStream.IsStreamOwner = true; // Makes the Close also Close the underlying stream
zipStream.Close();
}
}
}
///
/// Copy the contents of one to another.
///
/// The stream to source data from.
/// The stream to write data to.
/// The buffer to use during copying.
static public void StreamUtilsCopy(Stream source, Stream destination, byte[] buffer)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
if (destination == null)
{
throw new ArgumentNullException("destination");
}
if (buffer == null)
{
throw new ArgumentNullException("buffer");
}
// Ensure a reasonable size of buffer is used without being prohibitive.
if (buffer.Length < 128)
{
throw new ArgumentException("Buffer is too small", "buffer");
}
bool copying = true;
while (copying)
{
int bytesRead = source.Read(buffer, 0, buffer.Length);
if (bytesRead > 0)
{
destination.Write(buffer, 0, bytesRead);
}
else
{
destination.Flush();
copying = false;
}
}
}
public static IList GetFilePathsInZip(string zippedStateFilePath, string dirContainingModelStateFiles)
{
IList filePathsInZip = new List();
using (Stream stream = File.Open(zippedStateFilePath, FileMode.Open))
{
using (ZipInputStream zipInputStream = new ZipInputStream(stream))
{
zipInputStream.IsStreamOwner = false;
ZipEntry zipEntry = zipInputStream.GetNextEntry();
while (zipEntry != null)
{
string filePath = zipEntry.Name;
if (Path.IsPathRooted(filePath) && dirContainingModelStateFiles != null)
{
filePath = FileUtils.GetRelativePath(dirContainingModelStateFiles, filePath);
}
filePathsInZip.Add(filePath);
zipEntry = zipInputStream.GetNextEntry();
}
}
}
return filePathsInZip;
}
}
}