压缩文件时可以保持目录结构吗?

Can I maintain directory structure when zipping file?

我正在尝试压缩一些文件,但这些文件可能存在于不同的目录中。压缩部分工作正常,但我不知道如何让它保留压缩文件中的目录结构。

这是我目前的情况:

public static void CreateZipFile(IEnumerable<FileInfo> files, string archiveName)
{
  using (var stream = File.OpenWrite(archiveName))
  using (var archive = new ZipArchive(stream, ZipArchiveMode.Create))
  {
    foreach (var item in files)
    {
      archive.CreateEntryFromFile(item.FullName, item.Name, CompressionLevel.Optimal);
    }
  }
}

这可能吗?

@ErocM @Flydog57 提供的 link 正是您想要的。您没有正确利用 entryName 参数(调用 CreateEntryFromFile 时的第二个参数)。

独立于您要添加到存档的文件(来自不同文件夹的相同文件),您必须使用 C# api 提供给您的 entryName 参数来构建您的存档。

如果您的文件全名是 /tmp/myfile.txt,而您是 archive.CreateEntryFromFile(item.FullName, item.Name),那么存档条目名称将是 myfile.txt。没有创建文件夹,因为条目名称的名称中不包含文件夹结构。

但是,如果您调用 archive.CreateEntryFromFile(item.FullName, item.FullName),您将把文件夹结构放入存档中。

您可以尝试使用您的函数,只需将 item.Name 更改为 item.FullName

请注意,windows;例如,如果您的路径是 C:\tmp\myfile.txt,则无法正确提取存档。然后您可以添加一些小代码以从文件的全名中删除 C:

一些实施示例:

using System;
using System.IO;
using System.Collections.Generic;
using System.IO.Compression;

namespace ConsoleApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            FileInfo f1 = new FileInfo(@"/tmp/test1.txt");
            FileInfo f2 = new FileInfo(@"/tmp/testdir/test2.txt");

            List<FileInfo> files = new();
            files.Add(f1);
            files.Add(f2);

            CreateZipFile(files, @"/tmp/archive.zip");

        }

        public static void CreateZipFile(IEnumerable<FileInfo> files, string archiveName)
        {
            using (var stream = File.OpenWrite(archiveName))
            using (var archive = new ZipArchive(stream, ZipArchiveMode.Create))
            {
                foreach (var item in files)
                {
                    // Here for instance, I put all files in the input list in the same directory, without checking from where they are in the host file system.
                    archive.CreateEntryFromFile(item.FullName, $"mydir/{item.Name}", CompressionLevel.Optimal);

                    // Here, I am just using the actual full path of the file. Be careful on windows with the disk name prefix (C:, D:, etc...).
                    // archive.CreateEntryFromFile(item.FullName, item.FullName, CompressionLevel.Optimal);
                }
            }
        }
    }