From examples, I've got a pretty good grasp over how to extract a zip file.
In nearly every example, the method of identifying when a ZipEntry is a directory is as follows
string directoryName = Path.GetDirectoryName(theEntry.Name);
string fileName = Path.GetFileName(theEntry.Name);
if (directoryName.Length > 0)
Directory.CreateDirectory(Path.Combine(destinationDirectory, directoryName));
if (fileName != String.Empty)
{
//read data and write to file
}
Now is is fine and all (directory encountered, create it), directory is available when the file is extracted.
I can add files to a zip fine, but how do I add folders? I understand I'll be looping through the directories, adding the files encountered (and their ZipEntry.Name property is populated properly), but how do I add a ZipEntry to the archive and instruct the ZipOutputStream that it is a directory?
ZipFile.AddDirectory does what you want. Small sample code here.
Related
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.
I inherited some code that makes use of ZipArchive to save some information from the database. It uses BinaryFormatter to do this. When you look at the zip file with 7-zip (for example), you see a couple of folders and a .txt file. All is working well. I simply want to modify the code to also have a folder in the ZipArchive called "temp" that consists of files and folders under C:\temp. Is there an easy way to add a entry (ZipArchiveEntry?) that consist of an entire folder or the disc? I saw "CreateEntryFromFile" in the member methods of ZipArchive, but no CreateEntryFromDirectory. Or perhaps there's some other simple way to do it? Anyone have example code? I should say that C:\temp could have variable number of files and directories (that have child directories and files, etc.) Must I enumerate them somehow, create my own directories use CreateEntryFromFile? Any help is appreciated.
Similarly, when I read the ZipArchive, I want to take the stuff related to C:\temp and just dump it in a directory (like C:\temp_old)
Thanks,
Dave
The answer by user1469065 in Zip folder in C# worked for me. user1469065 shows how to get all the files/directories in the directory (using some cool "yield" statements) and then do the serialization. For completeness, I did add the code to deserialize as user1469065 suggested (at least I think I did it the way he suggested).
private static void ReadTempFileStuff(ZipArchive archive) // adw
{
var sessionArchives = archive.Entries.Where(x => x.FullName.StartsWith(#"temp_directory_contents")).ToArray();
if (sessionArchives != null && sessionArchives.Length > 0)
{
foreach (ZipArchiveEntry entry in sessionArchives)
{
FileInfo info = new FileInfo(#"C:\" + entry.FullName);
if (!info.Directory.Exists)
{
Directory.CreateDirectory(info.DirectoryName);
}
entry.ExtractToFile(#"C:\" + entry.FullName,true);
}
}
}
My code to zip files is as follows
ZipArchive zip = ZipFile.Open(destToZip, ZipArchiveMode.Create);
zip.CreateEntry("pubEd/");
string[] fileEntries = Directory.GetFiles(dirToZip);
foreach (string fileName in fileEntries)
zip.CreateEntryFromFile(fileName,Path.GetFileName(fileName), CompressionLevel.Optimal);
zip.Dispose();
In the second line of the code once after creating a zip file I create a folder with a name pubEd inside the zip file.
In the next line I am adding files to the zip folder.
What is happening is files get added to the zip directly.
I want to add these files inside the directory which I created inside the zip.
How do I do that?
By the looks of it you would changePath.GetFileName(fileName) to "pubEd/" + Path.GetFileName(fileName). And get rid of the second line. Thats just based on my reading of the documentation. I have not actually tried it.
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);
[...]
}
}
This is my code to update an existing zip, the callers pass in the ZipFile and have a finally block to close the zipfile.
private static void AddFiles(ZipFile zipFile, string path, string filesEntryLocation, string pattern = #"*") {
zipFile.BeginUpdate();
string[] files = Directory.GetFiles(path, pattern);
foreach (string filename in files) {
zipFile.Add(filename, (filesEntryLocation + filename.Split(new[] { '\\' }).Last()).Replace('\\','/'));
}
zipFile.CommitUpdate();
}
As you can see I'm adding entries into the zip and setting the entryname to be in a specific part of the zip folder hierarchy.
We are doing this to inject a product into a 'framework' web package - the framework supports loosely coupled products.
The result zip is fine, I can navigate it in Windows, I can extract it...
BUT MSDeploy comes along and where ever a new entry resulted in an addition to zip folder hierarchy, I get errors from msdeploy saying it couldn't open the zip - BUT only at that specific i.e. the zip is not completely corrupt, it's only where msdeploy starts navigating done a 'new' folder.
Now, if I extract the changed zip, and then re-zip it (using 7zip), and ask msdeploy to execute against that - no problem it works.
SO - is this SharpZipLib, or am I doing something wrong in adding to the zip folder hierarchy?
You should also add the folder entries to archive (if they do not exist before).