关于压缩:如何使用C#压缩文件,不使用第三方API?

How do I ZIP a file in C#, using no 3rd-party APIs?

我很确定这不是复制品,请稍等片刻。

如何在不使用任何第三方库的情况下(在Windows中)编程(c)压缩文件?我需要一个本地的Windows调用或类似的东西;我真的不喜欢启动一个进程的想法,但是如果我必须这样做的话,我会的。一个皮诺夫克电话会更好。

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


How can I programatically (C#) ZIP a file (in Windows) without using
any third party libraries?

如果使用4.5+框架,现在有了zipArchive和zipFile类。

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

您需要将引用添加到:

  • 系统IO压缩
  • system.io.compression.filesystem文件系统

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

  • 系统IO压缩
  • system.io.compression.zip文件

示例project.json:

1
2
3
4
5
6
7
8
"dependencies": {
 "System.IO.Compression":"4.1.0",
 "System.IO.Compression.ZipFile":"4.0.1"
},

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

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

  • 使用system.io.compression;


你在使用.NET 3.5吗?您可以使用ZipPackage类和相关类。它不仅仅是压缩文件列表,因为它需要为您添加的每个文件使用一个mime类型。它可以做你想做的。

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


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

您所要做的就是将[contentu types].xml文件添加到存档的根目录中,对于您希望包含的每个文件扩展名,都有一个"默认"节点。添加后,我可以从Windows资源管理器浏览该包,或者以编程方式解压缩并读取其内容。

有关[内容类型].xml文件的详细信息,请访问:http://msdn.microsoft.com/en-us/magazine/cc163372.aspx

以下是[contentu types].xml(必须准确命名)文件的示例:

1
2
3
4
5
6
7
8
9
10
11
12
<?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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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));
            }
        }
    }

注:

  • 此代码使用.NET 4.0中的stream.copyto方法
  • 通过在.NET 4.5中引入zipArchive类,这将变得更简单:http://msdn.microsoft.com/en-us/library/system.io.compression.zipArchive(v=vs.110).aspx


1
2
3
4
5
6
7
8
    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");
    }


对于.NET 2.0应用程序,我使用了sharpziplib。易于使用和开源。


基于Simon McKenzie对这个问题的回答,我建议使用以下两种方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    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);
    }
}


将这4个功能添加到项目中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
        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{}
        }
    }

像这样使用它们:

1
2
3
4
5
6
foreach (string f in UnitZipList)
{
    AddFileToZip(zipFile, f);
    System.IO.File.Delete(f);
}
Remove_Content_Types_FromZip(zipFile);

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

不幸的是,我不认为你会绕过开始一个单独的过程,除非你转到第三方组件。