Reputation: 83
I am trying to unzip all zips within a directory, which sometimes contain nested zips multiple layers down. I want to also preserve the original zip nesting structure in the extracted version. I am able to do what I want with one layer of zips, but not for nested zips or zips inside subfolders.
For example I want to turn everything in the starting folder like this:
[Starting Folder]
-Zip1.zip
--NestedZip1.zip
---text1.txt
--NestedZip2.zip
---text2.txt
-Zip2.zip
--[Subfolder1]
---Zip3.zip
----text3.txt
---Zip4.zip
----text4.txt
And extract everything to a folder in that same starting directory:
[Starting Folder]
[Extracted Folder]
-Zip1 (folder)
--NestedZip1 (folder)
---text1.txt
--NestedZip2 (folder)
---text2.txt
-Zip2 (folder)
--[Subfolder1]
---Zip3 (folder)
----text3.txt
---Zip4 (folder)
----text4.txt
Right now I am using this to unzip all the files in MyGlobals.finalPathForWork (which is the starting directory) and it works but only unzips one layer of zips. I need it to run again somehow in case there were zips in that first layer of zips.
public static void MyMethod3()
{
string startPath = MyGlobals.finalPathForWork;
string extractPath = MyGlobals.finalPathForWork + @"\\Extracted\";
Directory.GetFiles(startPath, "*.zip", SearchOption.AllDirectories).ToList()
.ForEach(zipFilePath =>
{
var extractPathForCurrentZip = Path.Combine(extractPath, Path.GetFileNameWithoutExtension(zipFilePath));
if (!Directory.Exists(extractPathForCurrentZip))
{
Directory.CreateDirectory(extractPathForCurrentZip);
}
ZipFile.ExtractToDirectory(zipFilePath, extractPathForCurrentZip);
});
}
I've tried applying/combining pieces of this: How to unzip multi layered zip files in C#
public static void ExtractFile(string baseZipPath, string extractPath)
{
if (!Directory.Exists(extractPath))
Directory.CreateDirectory(extractPath);
ZipFile.ExtractToDirectory(baseZipPath, extractPath);
string[] nestedZipDirectories = System.IO.Directory.GetFiles(extractPath, "*.zip");
foreach (var nestedZipDirectory in nestedZipDirectories)
{
ZipFile.ExtractToDirectory(nestedZipDirectory, extractPath);
}
}
static void Main(string[] args)
{
ExtractFile(@"c:\myfolder\grandfather.zip", @"c:\myfolder2");
}
Is there another way to loop the searching/unzipping process down through all subfolders and nested zip files? Or should that other solution above work and I'm must just be incorporating it incorrectly?
Upvotes: 1
Views: 2309
Reputation: 41
//Here is the complete working & tested code. Before running, just change the zipPath and extractPath.
static void Main(string[] args)
{
string zipPath = @"C:\TestZipFiles\test.zip";
string extractPath = @"C:\TestZipFiles\extractfiles";
int dbFileCount = 0;
ExtractRootFile(zipPath, extractPath, ref dbFileCount);
}
private static void DeleteSubFolderAndFiles(string destinationPath)
{
string[] fileEntries = Directory.GetFiles(destinationPath);
foreach (string fileName in fileEntries)
File.Delete(fileName);
string[] subdirectoryEntries =
Directory.GetDirectories(destinationPath);
foreach (string subdirectory in subdirectoryEntries)
{
DeleteSubFolderAndFiles(subdirectory);
if (Directory.GetFiles(subdirectory).Length == 0 &&
Directory.GetDirectories(subdirectory).Length == 0)
{
Directory.Delete(subdirectory);
}
}
}
public static void ExtractRootFile(string baseZipPath, string extractPath, ref int dbFileCount)
{
if (Directory.Exists(extractPath))
DeleteSubFolderAndFiles(extractPath);
if (!Directory.Exists(extractPath))
Directory.CreateDirectory(extractPath);
ZipFile.ExtractToDirectory(baseZipPath, extractPath);
extractPath = extractPath + @"\test"; //replace this with dynamic value of first zip file only.
RecursivelyExtractChildFolders(extractPath, ref dbFileCount);
}
public static void RecursivelyExtractChildFolders(string extractPath, ref int dbFileCount)
{
string[] nestedZipDirectories = System.IO.Directory.GetFiles(extractPath, "*.zip");
string[] nestedDBDirectories = System.IO.Directory.GetFiles(extractPath, "*.db");
if (nestedDBDirectories.Length > 0)
dbFileCount = dbFileCount + nestedDBDirectories.Length;
foreach (var nestedZipDirectory in nestedZipDirectories)
{
ZipFile.ExtractToDirectory(nestedZipDirectory, extractPath);
}
if (Directory.Exists(extractPath))
{
string[] subdirectoryEntries =
Directory.GetDirectories(extractPath);
foreach (string subdirectory in subdirectoryEntries)
{
RecursivelyExtractChildFolders(subdirectory, ref dbFileCount);
}
}
}
Upvotes: 0
Reputation: 82514
This is a classic use-case for recursion.
Note the comments in the code:
public static void ExtractFile(string zipFilePath, string extractPath)
{
// If directory already exist, CreateDirectory does nothing
Directory.CreateDirectory(extractPath);
// Extract current zip file
ZipFile.ExtractToDirectory(zipFilePath, extractPath);
// Enumerate nested zip files
var nestedZipFiles = Directory.EnumerateFiles(extractPath, "*.zip");
// iterate the enumerator
foreach (var nestedZipFile in nestedZipFiles)
{
// Get the nested zip full path + it's file name without the ".zip" extension
// I.E this "C:\users\YourUserName\Documents\SomeZipFile.Zip" - turns to this: "C:\users\YourUserName\Documents\SomeZipFile".
var nestedZipExtractPath = Path.Combine(Path.GetDirectoryName(nestedZipFile), Path.GetFileNameWithoutExtension(nestedZipFile));
// extract recursively
ExtractFile(nestedZipFile, nestedZipExtractPath);
}
}
Upvotes: 5