如何在不使用第三方 API 的情况下在 C# 中压缩文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/940582/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I ZIP a file in C#, using no 3rd-party APIs?
提问by Esteban Araya
I'm pretty sure this is not a duplicate so bear with me for just a minute.
我很确定这不是重复的,所以请耐心等待一分钟。
How can I programatically (C#) ZIP a file (in Windows) without using any third party libraries? I need a native windows call or something like that; I really dislike the idea of starting a process, but I will if I absolutely have to. A PInovke call would be much better.
如何在不使用任何第三方库的情况下以编程方式(C#)压缩文件(在 Windows 中)?我需要一个本机 Windows 调用或类似的东西;我真的不喜欢开始一个过程的想法,但如果我绝对需要,我会的。PInovke 调用会好得多。
Failing that, let me tell you what I'm really trying to accomplish: I need the ability to let a user download a collection of documents in a single request. Any ideas on how to accomplish this?
如果做不到这一点,让我告诉您我真正想要实现的目标:我需要能够让用户在单个请求中下载文档集合。关于如何实现这一点的任何想法?
采纳答案by Brian Ensink
Are you using .NET 3.5? You could use the ZipPackage
class and related classes. Its more than just zipping up a file list because it wants a MIME type for each file you add. It might do what you want.
您在使用 .NET 3.5 吗?您可以使用ZipPackage
该类和相关类。它不仅仅是压缩文件列表,因为它需要您添加的每个文件的 MIME 类型。它可能会做你想做的。
I'm currently using these classes for a similar problem to archive several related files into a single file for download. We use a file extension to associate the download file with our desktop app. One small problem we ran into was that its not possible to just use a third-party tool like 7-zip to create the zip files because the client side code can't open it -- ZipPackage adds a hidden file describing the content type of each component file and cannot open a zip file if that content type file is missing.
我目前正在使用这些类解决类似的问题,将几个相关文件归档到一个文件中以供下载。我们使用文件扩展名将下载文件与我们的桌面应用程序相关联。我们遇到的一个小问题是,不可能只使用像 7-zip 这样的第三方工具来创建 zip 文件,因为客户端代码无法打开它——ZipPackage 添加了一个描述内容类型的隐藏文件每个组件文件,如果缺少该内容类型文件,则无法打开 zip 文件。
回答by Dave Swersky
回答by Joshua
I was in the same situation, wanting to .NET instead of a third party library. As another poster mentioned above, simply using the ZipPackage class (introduced in .NET 3.5) is not quite enough. There is an additional file that MUST be included in the archive in order for the ZipPackage to work. If this file is added, then the resulting ZIP package can be opened directly from Windows Explorer - no problem.
我处于同样的情况,想要 .NET 而不是第三方库。正如上面提到的另一张海报,仅仅使用 ZipPackage 类(在 .NET 3.5 中引入)是不够的。为了使 ZipPackage 工作,存档中必须包含一个附加文件。如果添加了此文件,则可以直接从 Windows 资源管理器中打开生成的 ZIP 包 - 没问题。
All you have to do is add the [Content_Types].xml file to the root of the archive with a "Default" node for every file extension you wish to include. Once added, I could browse the package from Windows Explorer or programmatically decompress and read its contents.
您所要做的就是将 [Content_Types].xml 文件添加到存档的根目录,并为您希望包含的每个文件扩展名添加一个“默认”节点。添加后,我可以从 Windows 资源管理器浏览包或以编程方式解压缩并阅读其内容。
More information on the [Content_Types].xml file can be found here: http://msdn.microsoft.com/en-us/magazine/cc163372.aspx
有关 [Content_Types].xml 文件的更多信息,请访问:http: //msdn.microsoft.com/en-us/magazine/cc163372.aspx
Here is a sample of the [Content_Types].xml (must be named exactly) file:
以下是 [Content_Types].xml(必须准确命名)文件的示例:
<?xml version="1.0" encoding="utf-8" ?>
<Types xmlns=
"http://schemas.openxmlformats.org/package/2006/content-types">
<Default Extension="xml" ContentType="text/xml" />
<Default Extension="htm" ContentType="text/html" />
<Default Extension="html" ContentType="text/html" />
<Default Extension="rels" ContentType=
"application/vnd.openxmlformats-package.relationships+xml" />
<Default Extension="jpg" ContentType="image/jpeg" />
<Default Extension="png" ContentType="image/png" />
<Default Extension="css" ContentType="text/css" />
</Types>
And the C# for creating a ZIP file:
以及用于创建 ZIP 文件的 C#:
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))
{
source.CopyTo(File.OpenWrite(target));
}
}
}
Note:
笔记:
- This code uses the Stream.CopyTo method in .NET 4.0
- This will become much simpler with the introduction of the ZipArchive class in .NET 4.5: http://msdn.microsoft.com/en-us/library/system.io.compression.ziparchive(v=vs.110).aspx
- 此代码使用 .NET 4.0 中的 Stream.CopyTo 方法
- 随着 .NET 4.5 中 ZipArchive 类的引入,这将变得更加简单:http: //msdn.microsoft.com/en-us/library/system.io.compression.ziparchive(v=vs.110) .aspx
回答by GalacticJello
How can I programatically (C#) ZIP a file (in Windows) without using any third party libraries?
如何在不使用任何第三方库的情况下以编程方式(C#)压缩文件(在 Windows 中)?
If using the 4.5+ Framework, there is now the ZipArchiveand ZipFileclasses.
如果使用 4.5+ 框架,现在有ZipArchive和ZipFile类。
using (ZipArchive zip = ZipFile.Open("test.zip", ZipArchiveMode.Create))
{
zip.CreateEntryFromFile(@"c:\something.txt", "data/path/something.txt");
}
You need to add references to:
您需要添加对以下内容的引用:
- System.IO.Compression
- System.IO.Compression.FileSystem
- 系统.IO.压缩
- 系统.IO.压缩.文件系统
For .NET Core targeting net46, you need to add dependencies for
对于面向 net46 的 .NET Core,您需要为
- System.IO.Compression
- System.IO.Compression.ZipFile
- 系统.IO.压缩
- System.IO.Compression.Zip文件
Example project.json:
示例 project.json:
"dependencies": {
"System.IO.Compression": "4.1.0",
"System.IO.Compression.ZipFile": "4.0.1"
},
"frameworks": {
"net46": {}
}
For .NET Core 2.0, just adding a simple using statement is all that is needed:
对于 .NET Core 2.0,只需要添加一个简单的 using 语句即可:
- using System.IO.Compression;
- 使用 System.IO.Compression;
回答by mccdyl001
Based off Simon McKenzie's answer to this question, I'd suggest using a pair of methods like this:
基于 Simon McKenzie对这个问题的回答,我建议使用这样的一对方法:
public static void ZipFolder(string sourceFolder, string zipFile)
{
if (!System.IO.Directory.Exists(sourceFolder))
throw new ArgumentException("sourceDirectory");
byte[] zipHeader = new byte[] { 80, 75, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
using (System.IO.FileStream fs = System.IO.File.Create(zipFile))
{
fs.Write(zipHeader, 0, zipHeader.Length);
}
dynamic shellApplication = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
dynamic source = shellApplication.NameSpace(sourceFolder);
dynamic destination = shellApplication.NameSpace(zipFile);
destination.CopyHere(source.Items(), 20);
}
public static void UnzipFile(string zipFile, string targetFolder)
{
if (!System.IO.Directory.Exists(targetFolder))
System.IO.Directory.CreateDirectory(targetFolder);
dynamic shellApplication = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
dynamic compressedFolderContents = shellApplication.NameSpace(zipFile).Items;
dynamic destinationFolder = shellApplication.NameSpace(targetFolder);
destinationFolder.CopyHere(compressedFolderContents);
}
}
回答by FLICKER
private static string CompressFile(string sourceFileName)
{
using (ZipArchive archive = ZipFile.Open(Path.ChangeExtension(sourceFileName, ".zip"), ZipArchiveMode.Create))
{
archive.CreateEntryFromFile(sourceFileName, Path.GetFileName(sourceFileName));
}
return Path.ChangeExtension(sourceFileName, ".zip");
}
回答by Teemo
Add these 4 functions to your project:
将这 4 个函数添加到您的项目中:
public const long BUFFER_SIZE = 4096;
public static void AddFileToZip(string zipFilename, string fileToAdd)
{
using (Package zip = global::System.IO.Packaging.Package.Open(zipFilename, FileMode.OpenOrCreate))
{
string destFilename = ".\" + Path.GetFileName(fileToAdd);
Uri uri = PackUriHelper.CreatePartUri(new Uri(destFilename, UriKind.Relative));
if (zip.PartExists(uri))
{
zip.DeletePart(uri);
}
PackagePart part = zip.CreatePart(uri, "", CompressionOption.Normal);
using (FileStream fileStream = new FileStream(fileToAdd, FileMode.Open, FileAccess.Read))
{
using (Stream dest = part.GetStream())
{
CopyStream(fileStream, dest);
}
}
}
}
public static void CopyStream(global::System.IO.FileStream inputStream, global::System.IO.Stream outputStream)
{
long bufferSize = inputStream.Length < BUFFER_SIZE ? inputStream.Length : BUFFER_SIZE;
byte[] buffer = new byte[bufferSize];
int bytesRead = 0;
long bytesWritten = 0;
while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) != 0)
{
outputStream.Write(buffer, 0, bytesRead);
bytesWritten += bytesRead;
}
}
public static void RemoveFileFromZip(string zipFilename, string fileToRemove)
{
using (Package zip = global::System.IO.Packaging.Package.Open(zipFilename, FileMode.OpenOrCreate))
{
string destFilename = ".\" + fileToRemove;
Uri uri = PackUriHelper.CreatePartUri(new Uri(destFilename, UriKind.Relative));
if (zip.PartExists(uri))
{
zip.DeletePart(uri);
}
}
}
public static void Remove_Content_Types_FromZip(string zipFileName)
{
string contents;
using (ZipFile zipFile = new ZipFile(File.Open(zipFileName, FileMode.Open)))
{
/*
ZipEntry startPartEntry = zipFile.GetEntry("[Content_Types].xml");
using (StreamReader reader = new StreamReader(zipFile.GetInputStream(startPartEntry)))
{
contents = reader.ReadToEnd();
}
XElement contentTypes = XElement.Parse(contents);
XNamespace xs = contentTypes.GetDefaultNamespace();
XElement newDefExt = new XElement(xs + "Default", new XAttribute("Extension", "sab"), new XAttribute("ContentType", @"application/binary; modeler=Acis; version=18.0.2application/binary; modeler=Acis; version=18.0.2"));
contentTypes.Add(newDefExt);
contentTypes.Save("[Content_Types].xml");
zipFile.BeginUpdate();
zipFile.Add("[Content_Types].xml");
zipFile.CommitUpdate();
File.Delete("[Content_Types].xml");
*/
zipFile.BeginUpdate();
try
{
zipFile.Delete("[Content_Types].xml");
zipFile.CommitUpdate();
}
catch{}
}
}
And use them like this:
并像这样使用它们:
foreach (string f in UnitZipList)
{
AddFileToZip(zipFile, f);
System.IO.File.Delete(f);
}
Remove_Content_Types_FromZip(zipFile);