Сильно заменить существующие файлы во время извлечения файла с помощью 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);
}
}
}
Ответ 3
Взгляните на это: Легко создавать zip файлы в .NET 4.5. Ваша проблема, кажется, адресована. Кроме того, вы также можете проверить DotNetZip.
Ответ 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);
}
}
}