在使用System.IO.Compression提取文件期间强制替换现有文件
本文关键字:文件 替换 System IO Compression 提取 | 更新日期: 2023-09-27 17:58:36
我使用以下代码提取文件夹中的所有文件
using (ZipArchive archive = new ZipArchive(zipStream))
{
archive.ExtractToDirectory(location);
}
但如果存在一个文件,则会引发异常。是否有任何方法可以告诉压缩API替换现有文件。
我发现一种方法是先获取所有文件名,然后检查文件是否存在并删除它。但这对我来说代价高昂。
我已经创建了一个扩展。,任何对其改进的评论都将不胜感激
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);
}
}
}
当文件夹不存在时,此代码不会抛出异常,而不是创建文件夹。
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);
}
}
}
看看这个:在.NET 4.5中轻松创建zip文件。你的问题似乎得到了解决。或者,您也可以检查DotNetZip。
由于我是Linq的忠实粉丝,Linq的方式仅供参考:
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));
}
自.NET Standard 2.1以来,将overwriteFiles
设置为true非常简单:ZipFile.ExtractToDirectory(string sourceFile, string destDir, Encoding entryNameEncoding, bool overwriteFiles)
Example:
ZipFile.ExtractToDirectory("c:''file.zip","c:''destination_folder", Encoding.UTF8, true);
您可以将文件提取到某个临时目录,然后使用"File.Copy"与ovveride选项true到您的目标目录
我知道这不是一个完美的解决方案,但这样你就不需要检查文件是否存在
这里有一个方法,它获取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);
}
}
}
嗨,我正在使用从金块下载的DotNetZip。我只是简单地使用这个代码。这将自动替换目录中的文件(如果存在)。"超级安静"!
using (ZipFile archive = new ZipFile(@"" + System.Environment.CurrentDirectory + "''thezipfile.zip"))
{
archive.ExtractAll(@"" + System.Environment.CurrentDirectory, ExtractExistingFileAction.OverwriteSilently);
}
当您有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);
}
}
}
}
}
从答案中重新制作一个小方法来创建所有文件夹
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);
}
}
似乎避免包含该代码块的唯一方法是在使用del
:提取存档之前简单地删除文件
del (location + "'*")
using (ZipArchive archive = new ZipArchive(zipStream))
{
archive.ExtractToDirectory(location);
}
这并不完全是OP想要的,但它很紧凑。
一种更好的代码,
不检查目录是否存在(创建时会自动检查)
零堆分配(而不是用于的foreach)
使用
using var stream = someStream;
using var zipArchive = new ZipArchive(stream);
zipArchive.ExtractToDirectoryEx(path);
public static class ZipArchiveExtensions
{
[SuppressMessage("ReSharper", "ForCanBeConvertedToForeach")]
public static void ExtractToDirectoryEx(this ZipArchive source, string destinationDirectoryName)
{
var entries = source.Entries;
for (var i = 0; i < entries.Count; i++)
{
var entry = entries[i];
var completeFileName = Path.Combine(destinationDirectoryName, entry.FullName);
var directory = Path.GetDirectoryName(completeFileName);
Directory.CreateDirectory(directory);
if (entry.Name != string.Empty)
{
entry.ExtractToFile(completeFileName, overwrite: true);
}
}
}
}