提取存档条目将创建一个位于指定目标目录之外的文件

问题描述 投票:0回答:3

当尝试提取 .jar 文件时,我不断收到:

提取存档条目将创建一个位于指定目标目录之外的文件

有人可以帮助我吗?这是我的代码:

try
{
    using (ZipArchive archive = ZipFile.Open(jarLocationTXT.Text, ZipArchiveMode.Update))
    {
        archive.ExtractToDirectory(@"C:\Users\Neglekt\Monix Software\MCMI\CurExtract\");
    } 
}
catch (IOException ExtrEx)
{
    MessageBox.Show(ExtrEx.ToString());
    MessageBox.Show("An error occured while processing your data! \n Error code: E:002", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
c# jar extract unzip
3个回答
2
投票

如果创建 ZipArchiveEntry 时在文件路径开头使用了额外的 \,ZipFile.ExtractToDirectory 会认为文件路径位于 zip 文件之外。

ok: ZipArchiveEntry.CreateEntry("文件夹 ile.ext");

不行:ZipArchiveEntry.CreateEntry("older ile.ext"); 当使用 7zip 之类的工具打开 zip 包时,文件路径不正确,在图形用户界面中看起来类似于 _ old ile.ext。


1
投票

文档说,在以下情况下会抛出这样的异常:

例如,条目名称包含父目录访问器。

父目录访问器例如是

..
。当您在命令提示符下键入
cd ..
时,您是在告诉 change directory (
cd
) 程序转到父目录,这就是
..
的含义。因此会抛出异常,因为 zip 文件中的条目包含对某个父目录的引用。

在使用

ExtractToDirectory
时,似乎没有办法绕过该检查,因此一个选项是使用静态或扩展方法来滚动您自己的提取方法。我的意思是创建一个你自己的方法:

  1. 获取 zip 文件和目标目录的路径
  2. ZipArchive
    中打开文件。
  3. 迭代其
    Entries
  4. 使用提供的目标目录和条目中的相对路径将每个
    ZipArchiveEntry
    提取到文件中。

1
投票
如果 zip 包含空根目录,

ZipFile.ExtractToDirectory
将失败
/

请使用下面的

ZipFileEx.ExtractToDirectory
来代替:

namespace System.IO.Compression {
  public static class ZipFileEx {
    public static void ExtractToDirectory(string sourceArchiveFileName, string destinationDirectoryName) =>
    ExtractToDirectory(sourceArchiveFileName, destinationDirectoryName, entryNameEncoding: null, overwriteFiles: false);

    public static void ExtractToDirectory(string sourceArchiveFileName, string destinationDirectoryName, bool overwriteFiles) =>
        ExtractToDirectory(sourceArchiveFileName, destinationDirectoryName, entryNameEncoding: null, overwriteFiles: overwriteFiles);

    public static void ExtractToDirectory(string sourceArchiveFileName, string destinationDirectoryName, Encoding? entryNameEncoding) =>
        ExtractToDirectory(sourceArchiveFileName, destinationDirectoryName, entryNameEncoding: entryNameEncoding, overwriteFiles: false);

    public static void ExtractToDirectory(string sourceArchiveFileName, string destinationDirectoryName, Encoding? entryNameEncoding, bool overwriteFiles)
    {
      ArgumentNullException.ThrowIfNull(sourceArchiveFileName);
      ArgumentNullException.ThrowIfNull(destinationDirectoryName);

      using ZipArchive archive = ZipFile.Open(sourceArchiveFileName, ZipArchiveMode.Read, entryNameEncoding);

      foreach (ZipArchiveEntry entry in archive.Entries) {
        DirectoryInfo di = Directory.CreateDirectory(destinationDirectoryName);
        string destinationDirectoryFullPath = di.FullName;
        if (!destinationDirectoryFullPath.EndsWith(Path.DirectorySeparatorChar)) {
          char sep = Path.DirectorySeparatorChar;
          destinationDirectoryFullPath = string.Concat(destinationDirectoryFullPath, new ReadOnlySpan<char>(in sep));
        }

        string entryFullName = entry.FullName;
        if (entryFullName.Length > 0 && entryFullName[0] == '/') entryFullName = entryFullName[1..]; // remove leading root

        string fileDestinationPath = Path.GetFullPath(Path.Combine(destinationDirectoryFullPath, entryFullName.Replace('\0', '_')));

        var IsCaseSensitive = !(OperatingSystem.IsWindows() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS() || OperatingSystem.IsTvOS() || OperatingSystem.IsWatchOS());
        var stringComparison = IsCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;

        if (!fileDestinationPath.StartsWith(destinationDirectoryFullPath,stringComparison)) throw new IOException(@"Extracting Zip entry would have resulted in a file outside the specified destination directory.");

        if (Path.GetFileName(fileDestinationPath).Length == 0) {
          if (entry.Length != 0) throw new IOException(@"Zip entry name ends in directory separator character but contains data.");
          Directory.CreateDirectory(fileDestinationPath);

        } else {
          Directory.CreateDirectory(Path.GetDirectoryName(fileDestinationPath)!);
          entry.ExtractToFile(fileDestinationPath, overwrite: overwriteFiles);
        }
      }
    }
  }
}

上面是

ZipFile.ExtractToDirectory
的精确副本,除了检查
entryFullName[0] == '/'

的行之外
© www.soinside.com 2019 - 2024. All rights reserved.