如何创建 zip 存档仅包含具有特定扩展名的文件

How to create zip archive contains files with certain extensions only

我需要创建 zip 存档,它应该只包含具有特定扩展名的文件,但我需要保存原始目录的结构。

例如,我有一个结构如下的目录:

dir\
  sub_dir1\
    1.exe
  sub_dir_2\
    1.txt
    1.exe
  1.txt
  1.bat

我需要获取具有以下结构的存档(仅限 .exe 和 .bat 文件):

dir\
  sub_dir1\
    1.exe
  sub_dir_2\
    1.exe
  1.bat

我知道如何通过 Directory.GetFiles 方法找到这些文件:

var ext = new List<string> {".exe", ".bat"};
var myFiles = Directory.GetFiles(dir, "*.*", SearchOption.AllDirectories)
     .Where(s => ext.Any(e => s.EndsWith(e));

但那时我不知道如何保存存档的结构。

我怎样才能实现这种行为?

您可以从所有子目录中获取扩展名为 .exe 和 .bat 的所有文件,例如:

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()
        ;

然后根据这个 FileInfo 列表,您可以创建 zip 和文件夹 structure.You 可以找到文件信息详细信息 Here

System.IO.Directory.GetFiles("C:\temp", "*.exe", SearchOption.AllDirectories); 将 return 一个包含完整文件路径的数组,例如:

[C:\temp\dir1\app1.exe]
[C:\temp\dir2\subdir1\app2.exe]
[C:\temp\dir3\subdir2\subdir3\app3.exe]

因此,将这些文件放入带有 ZipArchive.CreateEntry 的 zip 容器中不会有任何问题,因为此方法将在 zip 中创建相同的目录结构。但是,您应该删除开头的 C:\

我相信这个非常好 tutorial 会帮助你做到这一点。

如果你想在目标 zip 中保留空文件夹,也许你必须使用 ZipArchive.CreateEntry 方法来做。在这个demo中,作者只使用ZipArchive. CreateEntryFromFile方法从一个文件路径归档一个文件。

您也可以使用 DotNetZip 库来解决您的问题。例如,以下代码片段可以帮助您。使用 CreateZip() 方法。简而言之,您应该找到用于写入存档 GetFileNames() 的文件并使用 CreateZipFromFileNames():

创建 zip 文件
    /// <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();
        }
    }

使用示例:

CreateZip("dir", new List<string> { "*.exe", "*.bat" }, "myFiles.zip");

@Didgeridoo 所说:DotNetZip. But DotNetZip 让您的表现力更上一层楼。例如:

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 ;
}

编辑注意: DotNetZip 曾经住在 Codeplex。 Codeplex 已关闭。旧存档仍然是 available at Codeplex。看起来代码已经迁移到 Github: