我有一堆ZIP文件迫切需要一些分层重组和提取。目前我能做的是创建目录结构并将zip文件移动到正确的位置。我缺少的神秘奶酪是从ZIP档案中提取文件的部分。
我已经在ZipArchive
课上看过MSDN文章并且理解它们很合理。我也见过VBScript ways to extract。这不是一个复杂的类,因此提取东西应该非常简单。事实上,它“主要”起作用。我已将下面的当前代码包含在内以供参考。
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
(或者 Anything )的某个地方。看来打开的包是空的。深入挖掘调试器显示私有成员_zipArchive显示它实际上有部分。具有正确名称和一切的零件。为什么GetParts
函数不能检索它们?我试过向ZipArchive开放,但没有帮助。哎呀。
答案 0 :(得分:47)
如果您正在操作ZIP文件,您可能需要查看第三方库来帮助您。
例如,最近更新过的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");
}
以下是更新现有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的ZIP64,或者对于包含超过65535个条目的存档,也是如此。
自由。开源
得到它 codeplex或direct download from windows.net - CodePlex已停产并存档
答案 1 :(得分:44)
来自MSDN,
在这个示例中,使用了Package类(而不是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();
}
}
答案 2 :(得分:30)
来自“ZipPackage Class”(MSDN):
虽然Packages通过ZipPackage类存储为Zip文件*,但所有Zip文件都不是ZipPackages。 ZipPackage具有特殊要求,例如符合URI的文件(部分)名称和“[Content_Types] .xml”文件,该文件定义包中包含的所有文件的MIME类型。 ZipPackage类不能用于打开不符合Open Packaging Conventions标准的任意Zip文件。
有关详细信息,请参阅ECMA国际“开放式包装约定”标准,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)的第9.2节“映射到ZIP存档”
*您只需将“.zip”添加到任何基于ZipPackage的文件(.docx,.xlsx,.pptx等)的扩展名,即可在您喜欢的Zip实用程序中打开它。
答案 3 :(得分:13)
我遇到了完全相同的问题!为了让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();
}
}
}
注意:此代码使用.NET 4.0中的Stream.CopyTo方法
答案 4 :(得分:6)
我同意奶酪。处理通用zip文件时,System.IO.Packaging很尴尬,因为它是为Office Open XML文档设计的。我建议使用DotNetZip或SharpZipLib
答案 5 :(得分:1)
(这基本上是this answer)
的改述原来System.IO.Packaging.ZipPackage
不支持PKZIP,这就是为什么当你打开“通用”ZIP文件时,不会返回“部分”。此类仅支持某些特定风格的ZIP文件(请参阅MSDN description底部的注释),其中包括用作SDK 1.6的Windows Azure服务包 - 这就是为什么如果解压缩服务包然后使用say重新打包它的原因Info-ZIP打包器将无效。