Как я могу получить действительные записи ZipArchive, если одна из них содержит недопустимые символы?

Я использую System.IO.Compression для извлечения содержимого некоторых файлов Zip. Проблема в том, что всякий раз, когда есть запись с именем файла, содержащим некоторые недопустимые символы Windows, возникает исключение. Я пробовал несколько вещей, но так и не нашел способа игнорировать плохие записи и извлечь хорошие. Пожалуйста, учтите, что изменение содержимого zip-файла невозможно для типа выполняемой нами обработки, поэтому я должен обработать файл как есть.

Система обычно обрабатывает файлы с несколькими записями, это число является переменным, но может быть до 300 записей в одном zip-файле, а иногда будет запись с именем файла, таким как 'myfile<name>.txt', которое содержит угловые скобки, которые явно являются недопустимыми символами. для Windows. Я действительно хочу проигнорировать эту запись и перейти к извлечению остальных записей в ZipArchive. Но похоже, что это невозможно.

Любая идея о том, как игнорировать плохие записи ZipArchive?

До сих пор я пробовал разные вещи, чтобы получить записи отдельно, но я всегда получаю одну и ту же ошибку исключения.

Вот некоторые из вещей, которые я пробовал до сих пор:

  • Реализация обычного способа перебора записей:

    foreach (ZipArchiveEntry entry in ZipArchive.Entries)
    
  • Попытка получить только одну запись по индексу (здесь такое же исключение, хотя первая запись действительна):

    ZipArchiveEntry entry = ZipArchive.Entries[0]
    
  • Применение фильтра с использованием лямбда-выражения для игнорирования недопустимых записей (также такое же исключение):

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

Ничего из этого не помогает, и исключение, которое я получаю каждый раз, выглядит следующим образом:

в System.IO.Path.CheckInvalidPathChars(строковый путь, логический checkAdditional) в System.IO.Path.GetFileName(строковый путь) в 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(Stream fileToExtract, Int32 maxDepthLevel, Attachment att) в C:\Users\myUser\Documents\Visual Studio 2015\Projects\ZipLibraryConsole\ZipLibraryConsole\MicrosoftExtraction.cs:строка 47

Это фрагмент реализованного кода:

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

person Juan Luis Hidalgo    schedule 15.02.2017    source источник
comment
Вы пробовали использовать другую библиотеку, например. DotNetZip или SharpZipLib?   -  person Thomas Levesque    schedule 16.02.2017
comment
Это известная ошибка. Вам придется использовать другую библиотеку, кроме .NET, которая может работать с архивами .zip, в которых есть записи с именами, не соответствующими правилам Windows. connect.microsoft.com/VisualStudio/feedback/details/808187/   -  person Peter Duniho    schedule 16.02.2017
comment
В настоящее время мы используем SharpZipLib, и он работает очень хорошо, но в последнее время у нас были некоторые проблемы с некоторыми zip-файлами, эффект, который мы наблюдаем, аналогичен ZipBomb, но в этом случае zip-файлы повреждены, другие библиотеки могут определить их быстро, но SharpZipLib не может, и он выполняет бесконечный цикл, добавляя и добавляя байты к извлеченному файлу на жестком диске, пока не закончится место. Итак, мы оцениваем другие библиотеки, и именно так мы придумали zip-библиотеку Microsoft.   -  person Juan Luis Hidalgo    schedule 16.02.2017
comment
Привет, Питер, твоя ссылка очень полезна, спасибо, что поделился ею, и очень жаль, что эта ошибка не будет исправлена ​​в .NET в ближайшее время. Помимо этой проблемы, библиотека очень хорошо сработала для нас во время проверки концепции в качестве замены SharpZipLib. Эх, придется искать другой вариант.   -  person Juan Luis Hidalgo    schedule 16.02.2017
comment
Проблема с Connect закрыта, так как не будет исправлена ​​(как это часто бывает с Connect), но, похоже, она была исправлена ​​в .NET Core: github.com/dotnet/corefx/issues/4991   -  person Thomas Levesque    schedule 16.02.2017
comment
Спасибо, Томас, ваш ответ очень ценен.   -  person Juan Luis Hidalgo    schedule 18.02.2017


Ответы (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 уродлив, и вы можете поймать определенные исключения, если это вас смущает. Согласно комментариям выше, это исправлено в .NET Core. (ОБНОВЛЕНИЕ: подтверждено, что это исправлено в .Net Core 3.1, возможно, раньше).

Кредит на это (частичное) исправление для https://www.codeproject.com/Tips/1007398/Avoid-Illegal-Characters-in-Path-error-in-ZipArchi и https://gist.github.com/rdavisau/b66df9c99a4b11c5ceff

Дополнительные указатели на исправление путей с недопустимыми символами (не только zip-файлы) в ZipFile.ExtractToDirectory Недопустимые символы в пути

person Jon R    schedule 13.05.2020