代码之家  ›  专栏  ›  技术社区  ›  Esteban Araya

如何在不使用第三方API的情况下用C#压缩文件?

  •  150
  • Esteban Araya  · 技术社区  · 15 年前

    我很确定这不是复制品,所以请耐心等我一会儿。

    如何在不使用任何第三方库的情况下以编程方式(在Windows中)压缩文件?我需要一个本地windows调用或类似的东西;我真的不喜欢开始一个过程的想法,但是如果我必须的话,我会的。打个皮诺维克电话会好得多。

    如果做不到这一点,让我告诉你我真正想要实现的目标:我需要让用户在一个请求中下载一组文档的能力。关于如何实现这一点有什么想法吗?

    8 回复  |  直到 15 年前
        1
  •  325
  •   GalacticJello    7 年前

    ZipArchive ZipFile

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

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

    • System.IO.Compression.FileSystem

    对于以net46为目标的.NET Core,您需要为添加依赖项

    • 系统IO压缩
    • System.IO.Compression.ZipFile

    示例project.json:

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

    • 使用系统IO压缩;
        2
  •  86
  •   adrianbanks    13 年前

    ZipPackage 类和相关类。它不仅仅是压缩一个文件列表,因为它希望为您添加的每个文件都有一个MIME类型。它可以做你想做的事。

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

        3
  •  12
  •   Joshua    12 年前

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

    您只需将[Content\u Types].xml文件添加到归档文件的根目录中,每个文件扩展名都有一个“Default”节点。添加后,我可以从Windows资源管理器浏览该包,或通过编程方式解压缩并读取其内容。

    http://msdn.microsoft.com/en-us/magazine/cc163372.aspx

    以下是[Content\u 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)); 
                } 
            } 
        } 
    

    注:

        4
  •  12
  •   FLICKER    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");
        }
    
        5
  •  1
  •   Community CDub    7 年前

    基于Simon McKenzie的回答 to this question

        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);
        }
    }
    
        6
  •  0
  •   Dave Swersky    15 年前

    看起来Windows可能会让你这么做 this ...

    不幸的是,我认为除非您使用第三方组件,否则您将无法开始单独的流程。

        7
  •  0
  •   Teemo    6 年前

            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);