Сильно заменить существующие файлы во время извлечения файла с помощью System.IO.Compression?

Я использую следующий код для извлечения всех файлов в папке

        using (ZipArchive archive = new ZipArchive(zipStream))
        {
            archive.ExtractToDirectory(location);
        }

Но если один файл существует, он выдает исключение. Есть ли способ сообщить API Compression заменить существующие файлы.

Я нашел один способ - сначала получить все имена файлов, а затем проверить, существует ли файл и удалить его. Но для меня это как-то очень дорого.

Ответы

Ответ 1

Я создал расширение. Любой комментарий к этому улучшению будет оценен,

public static class ZipArchiveExtensions
{
    public static void ExtractToDirectory(this ZipArchive archive, string destinationDirectoryName, bool overwrite)
    {
        if (!overwrite)
        {
            archive.ExtractToDirectory(destinationDirectoryName);
            return;
        }

        DirectoryInfo di = Directory.CreateDirectory(destinationDirectoryName);
        string destinationDirectoryFullPath = di.FullName;

        foreach (ZipArchiveEntry file in archive.Entries)
        {
            string completeFileName = Path.GetFullPath(Path.Combine(destinationDirectoryFullPath, file.FullName));

            if (!completeFileName.StartsWith(destinationDirectoryFullPath, StringComparison.OrdinalIgnoreCase))
            {
                throw new IOException("Trying to extract file outside of destination directory. See this link for more info: https://snyk.io/research/zip-slip-vulnerability");
            }

            if (file.Name == "")
            {// Assuming Empty for Directory
                Directory.CreateDirectory(Path.GetDirectoryName(completeFileName));
                continue;
            }
            file.ExtractToFile(completeFileName, true);
        }
    }
}

Ответ 2

Этот код не будет генерировать исключение, если папка не существует, вместо этого она создаст папку.

public static class ZipArchiveExtensions
{
    public static void ExtractToDirectory(this ZipArchive archive, string destinationDirectoryName, bool overwrite)
    {
        if (!overwrite)
        {
            archive.ExtractToDirectory(destinationDirectoryName);
            return;
        }
        foreach (ZipArchiveEntry file in archive.Entries)
        {
            string completeFileName = Path.Combine(destinationDirectoryName, file.FullName);
            string directory = Path.GetDirectoryName(completeFileName);

            if (!Directory.Exists(directory))
                Directory.CreateDirectory(directory);

            if (file.Name != "")
                file.ExtractToFile(completeFileName, true);
        }
    }
}

Ответ 4

Вы можете извлекать файлы в какой-то временный каталог и копировать файлы с помощью "File.Copy" с опцией ovveride true в ваш целевой каталог

Я знаю, что это не идеальное решение, но таким образом вам не нужно проверьте, существует ли файл

Ответ 5

Так как я настоящий фанат Linq, способ Linq-ish просто для справки:

using (var strm = File.OpenRead(zipPath))
using (ZipArchive a = new ZipArchive(strm))
{
    a.Entries.Where(o => o.Name == string.Empty && !Directory.Exists(Path.Combine(basePath, o.FullName))).ToList().ForEach(o => Directory.CreateDirectory(Path.Combine(basePath, o.FullName)));
    a.Entries.Where(o => o.Name != string.Empty).ToList().ForEach(e => e.ExtractToFile(Path.Combine(basePath, e.FullName), true));
}

Ответ 6

Небольшой переделанный метод из ответа для создания всех папок

public static void ExtractToDirectory(this ZipArchive archive, string destinationDirectoryName, bool overwrite)
{
    if (!overwrite)
    {
        archive.ExtractToDirectory(destinationDirectoryName);
        return;
    }
    foreach (ZipArchiveEntry file in archive.Entries)
    {
        string completeFileName = Path.Combine(destinationDirectoryName, file.FullName);
        if (file.Name == "")
        {// Assuming Empty for Directory
            Directory.CreateDirectory(Path.GetDirectoryName(completeFileName));
            continue;
        }
        // create dirs
        var dirToCreate = destinationDirectoryName;
        for (var i = 0; i < file.FullName.Split('/').Length - 1; i++)
        {
            var s = file.FullName.Split('/')[i];
            dirToCreate = Path.Combine(dirToCreate, s);
            if (!Directory.Exists(dirToCreate))
                Directory.CreateDirectory(dirToCreate);
        }
        file.ExtractToFile(completeFileName, true);
    }
}

Ответ 7

Это полезно, когда у вас есть путь к zip файлу

public static class ZipArchiveHelper
    {
        public static void ExtractToDirectory(string archiveFileName, string destinationDirectoryName, bool overwrite)
        {
            if (!overwrite)
            {
                ZipFile.ExtractToDirectory(archiveFileName, destinationDirectoryName);
            }
            else
            {
                using (var archive = ZipFile.OpenRead(archiveFileName))
                {

                    foreach (var file in archive.Entries)
                    {
                        var completeFileName = Path.Combine(destinationDirectoryName, file.FullName);
                        var directory = Path.GetDirectoryName(completeFileName);

                        if (!Directory.Exists(directory) && !string.IsNullOrEmpty(directory))
                            Directory.CreateDirectory(directory);

                        if (file.Name != "")
                            file.ExtractToFile(completeFileName, true);
                    }

                }
            }            
        }
    }

Ответ 8

Привет, я использую DotNetZip скачать с самородка. Я просто использую этот код. Это автоматически заменит файлы в каталоге, если он существует. "Перезаписать молча"!

using (ZipFile archive = new ZipFile(@"" + System.Environment.CurrentDirectory + "\\thezipfile.zip"))
{
     archive.ExtractAll(@"" + System.Environment.CurrentDirectory, ExtractExistingFileAction.OverwriteSilently);
}

Ответ 9

Вот метод, который берет путь к zip файлу.

На основании принятого ответа.

    public void ExtractZipFileToDirectory(string sourceZipFilePath, string destinationDirectoryName, bool overwrite)
    {
        using (var archive = ZipFile.Open(sourceZipFilePath, ZipArchiveMode.Read))
        {
            if (!overwrite)
            {
                archive.ExtractToDirectory(destinationDirectoryName);
                return;
            }

            DirectoryInfo di = Directory.CreateDirectory(destinationDirectoryName);
            string destinationDirectoryFullPath = di.FullName;

            foreach (ZipArchiveEntry file in archive.Entries)
            {
                string completeFileName = Path.GetFullPath(Path.Combine(destinationDirectoryFullPath, file.FullName));

                if (!completeFileName.StartsWith(destinationDirectoryFullPath, StringComparison.OrdinalIgnoreCase))
                {
                    throw new IOException("Trying to extract file outside of destination directory. See this link for more info: https://snyk.io/research/zip-slip-vulnerability");
                }

                if (file.Name == "")
                {// Assuming Empty for Directory
                    Directory.CreateDirectory(Path.GetDirectoryName(completeFileName));
                    continue;
                }
                file.ExtractToFile(completeFileName, true);
            }
        }
    }