使用 C# 和 System.IO.Packaging 以编程方式从 Zip 存档中提取文件
-
21-08-2019 - |
题
我有一堆 ZIP 文件,迫切需要进行一些分层重组和提取。目前我能做的是创建目录结构并将 zip 文件移动到正确的位置。我缺少的神秘奶酪是从 ZIP 存档中提取文件的部分。
我看过 MSDN 上的文章 ZipArchive
上课并合理地理解它们。我也看过 VBScript 提取方法. 。这不是一个复杂的类,因此提取内容应该非常简单。事实上,它“大部分”有效。我在下面包含了我当前的代码以供参考。
using (ZipPackage package = (ZipPackage)Package.Open(@"..\..\test.zip", FileMode.Open, FileAccess.Read))
{
PackagePartCollection packageParts = package.GetParts();
foreach (PackageRelationship relation in packageParts)
{
//Do Stuff but never gets here since packageParts is empty.
}
}
问题似乎出在某个地方 GetParts
(或获取任何事物 对于这个问题)。包裹打开后似乎是空的。深入挖掘调试器表明私有成员 _zipArchive 显示它实际上有部分。具有正确名称和一切的零件。为什么不会 GetParts
函数检索它们?我尝试过将 open 转换为 ZipArchive,但这没有帮助。咕噜。
解决方案
如果您正在操作 ZIP 文件,您可能需要查看第 3 方库来帮助您。
例如,最近更新的DotNetZip。目前的版本是 v1.8。以下是创建 zip 的示例:
using (ZipFile zip = new ZipFile())
{
zip.AddFile("c:\\photos\\personal\\7440-N49th.png");
zip.AddFile("c:\\Desktop\\2005_Annual_Report.pdf");
zip.AddFile("ReadMe.txt");
zip.Save("Archive.zip");
}
这是一个例子 更新 现有的邮政编码;您不需要解压文件来执行此操作:
using (ZipFile zip = ZipFile.Read("ExistingArchive.zip"))
{
// 1. remove an entry, given the name
zip.RemoveEntry("README.txt");
// 2. Update an existing entry, with content from the filesystem
zip.UpdateItem("Portfolio.doc");
// 3. modify the filename of an existing entry
// (rename it and move it to a sub directory)
ZipEntry e = zip["Table1.jpg"];
e.FileName = "images/Figure1.jpg";
// 4. insert or modify the comment on the zip archive
zip.Comment = "This zip archive was updated " + System.DateTime.ToString("G");
// 5. finally, save the modified archive
zip.Save();
}
这是提取条目的示例:
using (ZipFile zip = ZipFile.Read("ExistingZipFile.zip"))
{
foreach (ZipEntry e in zip)
{
e.Extract(TargetDirectory, true); // true => overwrite existing files
}
}
DotNetZip 支持文件名中的多字节字符、Zip 加密、AES 加密、流、Unicode、自解压存档。对于文件长度大于 0xFFFFFFFF 或条目数超过 65535 的存档,ZIP64 也是如此。
自由的。开源
得到它在代码复合体 或者 直接从 windows.net 下载 - CodePlex 已停产并存档
其他提示
从 MSDN ,
在此示例中,包类用于(而不是在ZipPackage)已经与这两个工作,我只看到当有在zip文件损坏片状发生。该包装部件有故障处理不一定腐败抛出Windows的提取或Winzip的,但事情。
希望这有助于,也许它可以为您提供替代调试问题。
using System;
using System.IO;
using System.IO.Packaging;
using System.Text;
class ExtractPackagedImages
{
static void Main(string[] paths)
{
foreach (string path in paths)
{
using (Package package = Package.Open(
path, FileMode.Open, FileAccess.Read))
{
DirectoryInfo dir = Directory.CreateDirectory(path + " Images");
foreach (PackagePart part in package.GetParts())
{
if (part.ContentType.ToLowerInvariant().StartsWith("image/"))
{
string target = Path.Combine(
dir.FullName, CreateFilenameFromUri(part.Uri));
using (Stream source = part.GetStream(
FileMode.Open, FileAccess.Read))
using (Stream destination = File.OpenWrite(target))
{
byte[] buffer = new byte[0x1000];
int read;
while ((read = source.Read(buffer, 0, buffer.Length)) > 0)
{
destination.Write(buffer, 0, read);
}
}
Console.WriteLine("Extracted {0}", target);
}
}
}
}
Console.WriteLine("Done");
}
private static string CreateFilenameFromUri(Uri uri)
{
char [] invalidChars = Path.GetInvalidFileNameChars();
StringBuilder sb = new StringBuilder(uri.OriginalString.Length);
foreach (char c in uri.OriginalString)
{
sb.Append(Array.IndexOf(invalidChars, c) < 0 ? c : '_');
}
return sb.ToString();
}
}
从 ”ZipPackage 类“(MSDN):
虽然包通过 ZipPackage 类存储为 Zip 文件*,但所有 Zip 文件都不是 ZipPackages。ZipPackage 具有特殊要求,例如符合 URI 的文件(部分)名称和定义包中包含的所有文件的 MIME 类型的“[Content_Types].xml”文件。ZipPackage 类不能用于打开不符合开放打包约定标准的任意 Zip 文件。
有关更多详细信息,请参阅 ECMA 国际“开放包装约定”标准的第 9.2 节“映射到 ZIP 存档”, http://www.ecma-international.org/publications/files/ECMA-ST/Office%20Open%20XML%20Part%202%20(DOCX).zip (342Kb) 或 http://www.ecma-international.org/publications/files/ECMA-ST/Office%20Open%20XML%20Part%202%20(PDF).zip (1.3MB)
*您只需将“.zip”添加到任何基于 ZipPackage 的文件(.docx、.xlsx、.pptx 等)的扩展名,即可在您最喜欢的 Zip 实用程序中打开它。
我有完全相同的问题!为了得到GETPARTS()方法返回的东西,我不得不添加[CONTENT_TYPES] .xml文件到文件的根目录与每个文件扩展名的“默认”节点包括在内。有一次,我加入这个(只是使用Windows资源管理器),我的代码是能够读取和提取存档内容。
上的[CONTENT_TYPES] .xml文件的更多信息可在这里找到:
http://msdn.microsoft.com/en-us/magazine/ cc163372.aspx - 有文章的图13下面的示例文件
var zipFilePath = "c:\\myfile.zip";
var tempFolderPath = "c:\\unzipped";
using (Package package = ZipPackage.Open(zipFilePath, FileMode.Open, FileAccess.Read))
{
foreach (PackagePart part in package.GetParts())
{
var target = Path.GetFullPath(Path.Combine(tempFolderPath, part.Uri.OriginalString.TrimStart('/')));
var targetDir = target.Remove(target.LastIndexOf('\\'));
if (!Directory.Exists(targetDir))
Directory.CreateDirectory(targetDir);
using (Stream source = part.GetStream(FileMode.Open, FileAccess.Read))
{
FileStream targetFile = File.OpenWrite(target);
source.CopyTo(targetFile);
targetFile.Close();
}
}
}
注意:此代码使用Stream.CopyTo方法在.NET 4.0
我同意芝士的观点。System.IO.Packaging 在处理通用 zip 文件时很尴尬,因为它是为 Office Open XML 文档设计的。我建议使用 点网压缩 或者 SharpZipLib