Reputation: 20746
I need to create zip archive which should contain files with certain extensions only, but I need to save the structure of the original directory.
For example, I have a directory with the following structure:
dir\
sub_dir1\
1.exe
sub_dir_2\
1.txt
1.exe
1.txt
1.bat
and I need to get an archive with the following structure (only .exe and .bat files):
dir\
sub_dir1\
1.exe
sub_dir_2\
1.exe
1.bat
I know how to find these files via Directory.GetFiles method:
var ext = new List<string> {".exe", ".bat"};
var myFiles = Directory.GetFiles(dir, "*.*", SearchOption.AllDirectories)
.Where(s => ext.Any(e => s.EndsWith(e));
but I don't know how to save the archive's structure then.
How can I achieve such behavior?
Upvotes: 1
Views: 3308
Reputation: 74277
What @Didgeridoo said: DotNetZip. But DotNetZip lets you be even more expressive. For instance:
string cwd = Environment.CurrentDirectory ;
try
{
Environment.CurrentDirectory = @"c:\root\of\directory\tree\to\be\zipped" ;
using ( ZipFile zipfile = new ZipFile() )
{
zipfile.AddSelectedFiles( "name = *.bat OR name = *.exe" , true ) ;
zipfile.Save( @"c:\foo\bar\my-archive.zip") ;
}
}
finally
{
Environment.CurrentDirectory = cwd ;
}
Edited To Note: DotNetZip used to live at Codeplex. Codeplex has been shut down. The old archive is still available at Codeplex. It looks like the code has migrated to Github:
Upvotes: 0
Reputation: 69
You can get all the files with extension .exe and .bat from all the sub directories like:
IList<FileInfo> info = null;
DirectoryInfo dirInfo = new DirectoryInfo(path);
info = dirInfo
.GetFiles("*.*", SearchOption.AllDirectories)
.Where( f => f.Extension
.Equals(".exe", StringComparison.CurrentCultureIgnoreCase)
|| f.Extension
.Equals(".bat", StringComparison.CurrentCultureIgnoreCase)
)
.ToList()
;
Then based on this FileInfo list you can create you zip and folder structure.You can find the fileinfo details Here
Upvotes: 2
Reputation: 1262
Also you can use DotNetZip library for solving your problem. For example the following code snippet can help you. Use CreateZip()
method. In brief you should find files for writing to archive GetFileNames()
and create zip file using CreateZipFromFileNames()
:
/// <summary>
/// Create zip archive from root directory with search patterns
/// </summary>
/// <param name="rootDirectory">Root directory</param>
/// <param name="searchPatterns">Search patterns</param>
/// <param name="zipFileName">Zip archive file name</param>
public static void CreateZip(string rootDirectory, List<string> searchPatterns, string zipFileName)
{
var fileNames = GetFileNames(rootDirectory, searchPatterns, true);
CreateZipFromFileNames(rootDirectory, zipFileName, fileNames);
}
/// <summary>
/// Get file names filtered by search patterns
/// </summary>
/// <param name="rootDirectory">Root diirectory</param>
/// <param name="searchPatterns">Search patterns</param>
/// <param name="includeSubdirectories">True if it is included files from subdirectories</param>
/// <returns>List of file names</returns>
private static IEnumerable<string> GetFileNames(string rootDirectory, List<string> searchPatterns, bool includeSubdirectories)
{
var foundFiles = new List<string>();
var directoriesToSearch = new Queue<string>();
directoriesToSearch.Enqueue(rootDirectory);
// Breadth-First Search
while (directoriesToSearch.Count > 0)
{
var path = directoriesToSearch.Dequeue();
foreach (var searchPattern in searchPatterns)
{
foundFiles.AddRange(Directory.EnumerateFiles(path, searchPattern));
}
if (includeSubdirectories)
{
foreach (var subDirectory in Directory.EnumerateDirectories(path))
{
directoriesToSearch.Enqueue(subDirectory);
}
}
}
return foundFiles;
}
/// <summary>
/// Create zip archive from list of file names
/// </summary>
/// <param name="rootDirectroy">Root directory (for saving required structure of directories)</param>
/// <param name="zipFileName">File name of zip archive</param>
/// <param name="fileNames">List of file names</param>
private static void CreateZipFromFileNames(string rootDirectroy, string zipFileName, IEnumerable<string> fileNames)
{
var rootZipPath = Directory.GetParent(rootDirectroy).FullName;
using (var zip = new ZipFile(zipFileName))
{
foreach (var filePath in fileNames)
{
var directoryPathInArchive = Path.GetFullPath(Path.GetDirectoryName(filePath)).Substring(rootZipPath.Length);
zip.AddFile(filePath, directoryPathInArchive);
}
zip.Save();
}
}
Example of use:
CreateZip("dir", new List<string> { "*.exe", "*.bat" }, "myFiles.zip");
Upvotes: 0
Reputation: 582
I believe this very nice tutorial will help you to do that.
If you want to keep empty folder in the target zip, maybe you have to use ZipArchive.CreateEntry
method to do. In this demo, the author only use ZipArchive. CreateEntryFromFile
method to archive a file from a file path.
Upvotes: 1
Reputation: 5737
System.IO.Directory.GetFiles("C:\\temp", "*.exe", SearchOption.AllDirectories);
will return an array with the full file paths like:
[C:\temp\dir1\app1.exe]
[C:\temp\dir2\subdir1\app2.exe]
[C:\temp\dir3\subdir2\subdir3\app3.exe]
So you won't have any trouble to put these files in a zip container with ZipArchive.CreateEntry because this method will create the same directory structure in the zip. However, you should remove the C:\
at the beginning.
Upvotes: 1