Как обрабатывать распаковку ZipFile с слишком длинными/повторяющимися путями

При распаковке файлов в Windows у меня иногда возникают проблемы с путями

  • которые слишком длинны для Windows (но все в порядке, в исходной ОС, которая создала файл).
  • которые являются "дублирующимися" из-за нечувствительности к регистру.

Используя DotNetZip, вызов ZipFile.Read(path) будет записываться при чтении zip файлов с одной из этих проблем. Это означает, что я даже не могу его фильтровать.

using (ZipFile zip = ZipFile.Read(path))
{
    ...
}

Каков наилучший способ обработки этих файлов?

Обновлено:

Пример zip отсюда: https://github.com/MonoReports/MonoReports/zipball/master

Дубликаты: https://github.com/MonoReports/MonoReports/tree/master/src/MonoReports.Model/DataSourceType.cs https://github.com/MonoReports/MonoReports/tree/master/src/MonoReports.Model/DatasourceType.cs

Подробнее об исключении:

Ionic.Zip.ZipException: не может прочитать это как ZipFile
--- > System.ArgumentException: элемент > с тем же ключом уже добавлен.
  в System.ThrowHelper.ThrowArgumentException(ресурс ExceptionResource)
  в System.Collections.Generic.Dictionary 2.Insert(TKey key, TValue value, Boolean add)
at System.Collections.Generic.Dictionary
2.Add(ключ TKey, значение TValue)
  в Ionic.Zip.ZipFile.ReadCentralDirectory(ZipFile zf)
  на Ionic.Zip.ZipFile.ReadIntoInstance(ZipFile zf)

Разрешение:

Основываясь на предложении @Cheeso, я могу читать все из потока, избегать дубликатов и проблем с контентом:

//using (ZipFile zip = ZipFile.Read(path))
using (ZipInputStream stream = new ZipInputStream(path))
{
    ZipEntry e;
    while( (e = stream.GetNextEntry()) != null )
    //foreach( ZipEntry e in zip)
    {
        if (e.FileName.ToLower().EndsWith(".cs") ||
            e.FileName.ToLower().EndsWith(".xaml"))
        {
            //var ms = new MemoryStream();
            //e.Extract(ms);
            var sr = new StreamReader(stream);
            {
                //ms.Position = 0;
                CodeFiles.Add(new CodeFile() { Content = sr.ReadToEnd(), FileName = e.FileName });
            }
        }
    }
}

Ответ 1

Прочитайте его с помощью ZipInputStream.

Класс ZipFile хранит коллекцию, используя имя файла как индекс. Дублированные имена файлов ломают эту модель.

Но вы можете использовать ZipInputStream для чтения в вашем zip файле. В этом случае нет коллекции или индекса.

Ответ 2

Для проблемы PathTooLongException я обнаружил, что вы не можете использовать DotNetZip. Вместо этого я сделал ссылку версия командной строки 7-zip; который творит чудеса.

public static void Extract(string zipPath, string extractPath)
{
    try
    {
        ProcessStartInfo processStartInfo = new ProcessStartInfo
        {
            WindowStyle = ProcessWindowStyle.Hidden,
            FileName = Path.GetFullPath(@"7za.exe"),
            Arguments = "x \"" + zipPath + "\" -o\"" + extractPath + "\""
        };
        Process process = Process.Start(processStartInfo);
        process.WaitForExit();
        if (process.ExitCode != 0) 
        {
            Console.WriteLine("Error extracting {0}.", extractPath);
        }
    }
    catch (Exception e)
    {
        Console.WriteLine("Error extracting {0}: {1}", extractPath, e.Message);
        throw;
    }
}