【问题标题】:How can I get the valid Entries of a ZipArchive when one them contains illegal characters?当 ZipArchive 的一个条目包含非法字符时,如何获取它们的有效条目?
【发布时间】:2017-07-04 20:37:54
【问题描述】:

我正在使用 System.IO.Compression 来提取一些 Zip 文件的内容。问题是,只要有一个文件名包含某些 Windows 非法字符的条目,就会引发异常。我已经尝试了几件事,但我仍然没有找到任何方法来忽略不良条目并提取好的条目。请考虑修改 zip 文件的内容对于我们正在执行的处理类型是不可能的,所以我必须按原样处理文件。

系统通常会处理多个条目的文件,这个数字是可变的,但一个zip文件最多可以有300个条目,偶尔会有一个文件名如'myfile<name>.txt'的条目,其中包含尖括号这显然是 Windows 的非法字符。我真的很想忽略此条目并继续提取 ZipArchive 中的其余条目。但看起来这是不可能的。

知道如何忽略 ZipArchive 的不良条目吗?

到目前为止,我已经尝试了不同的方法来分别获取条目,但我总是得到完全相同的异常错误。

以下是我迄今为止尝试过的一些事情:

  • 实现迭代条目的常规方式:

    foreach (ZipArchiveEntry entry in ZipArchive.Entries)
    
  • 试图通过索引只获取一个条目(即使第一个条目是有效的,这里也是同样的例外):

    ZipArchiveEntry entry = ZipArchive.Entries[0]
    
  • 使用 lambda 表达式应用过滤器以忽略无效条目(同样的例外):

    var entries = zipArchive.Entries.Where(a => 
    a.FullName.IndexOfAny(Path.GetInvalidFileNameChars() ) == -1);
    

这没有任何帮助,我每次遇到的异常如下:

在 System.IO.Path.CheckInvalidPathChars(字符串路径,布尔值 checkAdditional) 在 System.IO.Path.GetFileName(String path) 在 System.IO.Compression.ZipHelper.EndsWithDirChar(字符串测试)在 System.IO.Compression.ZipArchiveEntry.set_FullName(字符串值)在 System.IO.Compression.ZipArchiveEntry..ctor(ZipArchive 存档, ZipCentralDirectoryFileHeader cd) 在 System.IO.Compression.ZipArchive.ReadCentralDirectory() 在 System.IO.Compression.ZipArchive.get_Entries() 在 ZipLibraryConsole.MicrosoftExtraction.RecursiveExtract(流 fileToExtract, Int32 maxDepthLevel, 附件 att) 在 C:\Users\myUser\Documents\Visual Studio 2015\Projects\ZipLibraryConsole\ZipLibraryConsole\MicrosoftExtraction.cs:line 47

这是实现代码的sn-p:

var zipArchive = new ZipArchive(fileToExtract, ZipArchiveMode.Read);
  try
    {
      foreach (var zipEntry in zipArchive.Entries) // the exception is thrown  here, there is no chance to process valid entries at all
      {
        // Do something and extract the file
      }
    catch (ArgumentException exception)
    {
      Console.WriteLine(
        String.Format("Failed to complete the extraction. At least one path contains invalid characters for the Operating System: {0}{1}",                       att.Name, att.Extention));
     }

【问题讨论】:

  • 您是否尝试过使用不同的库,例如DotNetZip 还是 SharpZipLib?
  • 这是一个已知的错误。您将不得不使用 .NET 以外的其他库,该库可以容纳 .zip 存档,其中包含名称不符合 Windows 规则的条目。 connect.microsoft.com/VisualStudio/feedback/details/808187/…
  • 我们目前使用的是SharpZipLib,效果很好,但是我们最近在处理一些zip文件时遇到了一些问题,我们观察到的效果类似于ZipBomb,但在这种情况下,zip文件已损坏,其他库能够快速识别这些,但 SharpZipLib 不能,它会通过无限循环向硬盘驱动器中的提取文件添加和添加字节,直到空间不足。所以我们正在评估其他库,这就是我们提出微软 zip 库的方式。
  • 嘿,彼得,您的链接非常有用,感谢您的分享,很遗憾这个错误不会很快在 .NET 中得到修复。除了这个问题之外,在概念验证期间,该库作为 SharpZipLib 的替代品对我们来说效果很好。哦,伙计,我将不得不寻找另一种选择。
  • Connect 上的问题已关闭为“无法修复”(Connect 上经常出现这种情况),但它似乎已在 .NET Core 中得到修复:github.com/dotnet/corefx/issues/4991

标签: c# .net ziparchive argumentexception illegal-characters


【解决方案1】:

使用 System.Reflection,您至少可以隐藏错误,尽管您只能获取路径中包含非法字符的条目。

添加此类并使用archive.GetRawEntries() 代替archive.Entries

public static class ZipArchiveHelper
{
    private static FieldInfo _Entries;
    private static MethodInfo _EnsureDirRead;
    static ZipArchiveHelper()
    {
        _Entries = typeof(ZipArchive).GetField("_entries", BindingFlags.NonPublic | BindingFlags.Instance);
        _EnsureDirRead = typeof(ZipArchive).GetMethod("EnsureCentralDirectoryRead", BindingFlags.NonPublic | BindingFlags.Instance);
    }
    public static List<ZipArchiveEntry> GetRawEntries(this ZipArchive archive)
    {
        try { _EnsureDirRead.Invoke(archive, null); } catch { }
        return (List<ZipArchiveEntry>)_Entries.GetValue(archive);
    }
}

try-catch 很丑陋,如果它让您感到困扰,您可以捕获特定的异常。 根据上面的 cmets,这是在 .NET Core 中修复的。 (更新:确认此问题已在 .Net Core 3.1 中修复,可能更早)。

将此(部分)修复归功于https://www.codeproject.com/Tips/1007398/Avoid-Illegal-Characters-in-Path-error-in-ZipArchihttps://gist.github.com/rdavisau/b66df9c99a4b11c5ceff

更多关于使用非法字符(不仅仅是 zip 文件)修复路径的指针ZipFile.ExtractToDirectory "Illegal characters in path"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-07
    • 1970-01-01
    • 2022-01-22
    • 2014-09-16
    • 1970-01-01
    相关资源
    最近更新 更多