如何不使用任何第三方API在C#中压缩文件?


175

我很确定这不是重复的,所以请耐心等待一分钟。

如何在不使用任何第三方库的情况下以编程方式(C#)对文件进行ZIP(在Windows中)?我需要一个本地Windows调用或类似的东西;我真的不喜欢启动流程的想法,但是如果绝对需要的话,我会的。PInovke电话会好得多。

失败了,让我告诉您我真正想要实现的目标:我需要能够让用户在单个请求中下载一系列文档的功能。关于如何实现此目标的任何想法?



1
@Chesso:是的,来自ASPX页面。
Esteban Araya

1
几周前我搜索相同的内容时,我发现此示例
很有用

2
如果使用4.5 Framework,则现在有ZipArchive和ZipFile类。
GalacticJello

有人使用过DotNetZip吗?
2014年

Answers:


85

您正在使用.NET 3.5吗?您可以使用ZipPackage该类和相关类。它不只是压缩文件列表,还因为它需要添加的每个文件的MIME类型。它可能会做您想要的。

我目前正在使用这些类来解决类似的问题,以将多个相关文件归档到单个文件中进行下载。我们使用文件扩展名将下载文件与桌面应用程序相关联。我们遇到的一个小问题是,不能仅使用7-zip之类的第三方工具来创建zip文件,因为客户端代码无法打开它-ZipPackage添加了一个隐藏文件来描述内容的类型每个组件文件,如果缺少该内容类型文件,则无法打开zip文件。


1
哦,我多么爱你!谢谢布莱恩;yuo只是为我们节省了很多头疼和一些麻烦。
Esteban Araya

6
请注意,这并不总是相反。某些Zip文件不会使用ZipPackage类重新补水。用ZipPackage制作的文件可以使您一切都好。
克雷格

请注意,ZipPackage不能追加到现有的压缩包中。
ΩmegaMan

一声叹息:“类型或命名空间‘包装’命名空间中不存在‘System.IO’。
热舔

2
(回答上述“感叹”:打开“参考”,然后添加(在逻辑上不够)“ WindowsBase”。)
热门问题

307

如何在不使用任何第三方库的情况下以编程方式(C#)对文件进行ZIP(在Windows中)?

如果使用4.5+框架,则现在有ZipArchiveZipFile类。

using (ZipArchive zip = ZipFile.Open("test.zip", ZipArchiveMode.Create))
{
    zip.CreateEntryFromFile(@"c:\something.txt", "data/path/something.txt");
}

您需要添加对以下内容的引用:

  • System.IO。压缩
  • System.IO.Compression.FileSystem

对于定位为net46的.NET Core,您需要为

  • System.IO。压缩
  • System.IO.Compression.ZipFile

示例project.json:

"dependencies": {
  "System.IO.Compression": "4.1.0",
  "System.IO.Compression.ZipFile": "4.0.1"
},

"frameworks": {
  "net46": {}
}

对于.NET Core 2.0,只需添加一个简单的using语句即可:

  • 使用System.IO.Compression;

4
怎么没有更多的投票呢?这是唯一的直接答案。
Matt Cashatt 2014年

12
因为问题是五年,而这个答案只有两个月。
Derp

3
@heliac Stackoverflow仍然是一个问题和答案的存储库,本着最好的答案应该是最好的答案……(该死,我知道这行不通)
Offler 2014年

5
万一它对任何人都有帮助,第二个参数是文件条目。这是相对于解压缩文件夹将文件提取到的路径。在Windows 7中,我发现如果文件条目是完整路径,例如@“ D:\ Temp \ file1.pdf”,则本机Windows提取程序将失败。如果仅使用Directory.GetFiles()生成的文件名,则可能会遇到此问题。最好使用Path.GetFileName()作为文件输入参数来提取文件名。
Manish 2014年

2
我似乎无法在4.5.2中找到它?
user3791372

11

我当时处在同样的情况下,想要使用.NET而不是第三方库。正如上面提到的另一幅海报,仅使用ZipPackage类(在.NET 3.5中引入)还不够。为了使ZipPackage工作,必须在存档中包含一个附加文件。如果添加了此文件,则可以直接从Windows资源管理器中打开生成的ZIP包-没问题。

您要做的就是将[Content_Types] .xml文件添加到存档的根目录,并为每个要包括的文件扩展名添加一个“默认”节点。添加后,我可以从Windows资源管理器中浏览该程序包或以编程方式解压缩并读取其内容。

有关[Content_Types] .xml文件的更多信息,可以在这里找到:http : //msdn.microsoft.com/zh-cn/magazine/cc163372.aspx

这是[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>

以及用于创建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)); 
            } 
        } 
    } 

注意:


12
不错的示例,但它不会创建ZIP文件。它解压缩现有文件。
Matt Varblow 2012年

9
    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");
    }

当我在webapi中并收到HttpContext.Current.Request时如何获取sourceFileName?
Olivertech '18

压缩多个文件?
Kiquenet '19

1

基于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);
    }
}


0

将以下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{}
        }
    }

并像这样使用它们:

foreach (string f in UnitZipList)
{
    AddFileToZip(zipFile, f);
    System.IO.File.Delete(f);
}
Remove_Content_Types_FromZip(zipFile);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.