使用 C# 压缩单个文件

Posted

技术标签:

【中文标题】使用 C# 压缩单个文件【英文标题】:Compress a single file using C# 【发布时间】:2014-09-22 09:48:47 【问题描述】:

我正在使用 .NET 4.5,如果我尝试使用“CreateFromDirectory”压缩整个目录,则 ZipFile 类效果很好。但是,我只想压缩目录中的一个文件。我尝试指向特定文件(文件夹\data.txt),但这不起作用。我考虑了 ZipArchive 类,因为它有一个“CreateEntryFromFile”方法,但似乎这只允许您在现有文件中创建一个条目。

有没有办法简单地压缩一个文件而不创建一个空的压缩文件(这有它的问题),然后使用 ZipArchiveExtension 的“CreateEntryFromFile”方法?

**这也是假设我正在开发一个目前无法使用第三方插件的公司程序。

示例来自:http://msdn.microsoft.com/en-us/library/ms404280%28v=vs.110%29.aspx

        string startPath = @"c:\example\start";
        string zipPath = @"c:\example\result.zip";
        string extractPath = @"c:\example\extract";

        ZipFile.CreateFromDirectory(startPath, zipPath);

        ZipFile.ExtractToDirectory(zipPath, extractPath);

但如果 startPath 为@"c:\example\start\myFile.txt;",则会抛出目录无效的错误。

【问题讨论】:

but that doesn't work 什么不起作用?你的代码在哪里? 指向特定文件不适用于“CreateFromDirectory”。我将微软示例添加到原始问题中。 您可以使用 ZipArchive 类创建一个新的 Zip 存档,尽管它并不完全是单行的。请参阅answer here 了解如何操作。 (如果这太麻烦,您可能会考虑使用更好的 3rd-party 库来处理 ZIP,例如DotNetZip) 或者您可以将文件移动到临时文件夹进行压缩,并在删除后提取到同一个临时文件夹?最好的解决方案是获得更好的库。 @elgonzo 我提到我不能使用 3rd-party 解决方案,但感谢您的建议。似乎引用答案中的人正在尝试从头开始创建新文件并写入流,但我会尝试从那里找到解决方案。谢谢。 【参考方案1】:

使用存档中的CreateEntryFromFile 并使用文件或内存流:

如果您可以创建 zip 文件然后添加到其中,请使用文件流:

using (FileStream fs = new FileStream(@"C:\Temp\output.zip",FileMode.Create))
using (ZipArchive arch = new ZipArchive(fs, ZipArchiveMode.Create))

    arch.CreateEntryFromFile(@"C:\Temp\data.xml", "data.xml");

或者,如果您需要在内存中执行所有操作并在完成后写入文件,请使用内存流:

using (MemoryStream ms = new MemoryStream())
using (ZipArchive arch = new ZipArchive(ms, ZipArchiveMode.Create))

    arch.CreateEntryFromFile(@"C:\Temp\data.xml", "data.xml");

那你可以write the MemoryStream to a file。

using (FileStream file = new FileStream("file.bin", FileMode.Create, System.IO.FileAccess.Write)) 
   byte[] bytes = new byte[ms.Length];
   ms.Read(bytes, 0, (int)ms.Length);
   file.Write(bytes, 0, bytes.Length);
   ms.Close();

【讨论】:

这应该是公认的解决方案。虽然 AlexanderBrevig 的解决方案可能有效,但临时创建文件夹以制作 zip 文件涉及许多不必要的额外步骤。 John Koerner 的解决方案更简单,但可能更简单。如果您用 FileStream 代替他的 MemoryStream,则不需要将 MemoryStream 写入磁盘的第二步。也许有我不知道的速度或内存使用优势,但如果最终目标是 ZIP 文件,则直接转到 FileStream 会更好。 仅供参考:使用 ZipArchive 时,需要将 System.IO.Compression 引用添加到您的项目。不仅是System.IO.Compression.FileSystem【参考方案2】:

使用文件(或任何)流:

using (var zip = ZipFile.Open("file.zip", ZipArchiveMode.Create))

    var entry = zip.CreateEntry("file.txt");
    entry.LastWriteTime = DateTimeOffset.Now;

    using (var stream= File.OpenRead(@"c:\path\to\file.txt"))
    using (var entryStream = entry.Open())
        stream.CopyTo(entryStream);

或更简单:

// reference System.IO.Compression
using (var zip = ZipFile.Open("file.zip", ZipArchiveMode.Create))
    zip.CreateEntryFromFile("file.txt", "file.txt");

确保添加对 System.IO.Compression 的引用

更新

另外,请查看 ZipFile 和 ZipArchive 的新 dotnet API 文档。那里有几个例子。还有一个关于引用System.IO.Compression.FileSystem 以使用ZipFile 的警告。

要使用 ZipFile 类,您必须引用 项目中的 System.IO.Compression.FileSystem 程序集。

【讨论】:

可能是个愚蠢的问题....但是即使在添加 dll 引用之后,ZipArchiveMode 也不能被识别为 System.IO.Compression 命名空间的一部分。我看到它已记录在案,但 VS2012 似乎无法找到它(“当前上下文中不存在名称 'ZipArchiveMode'”)? @Ang 确保添加对 System.IO.Compression 的引用。如果你想使用CreatEntryFromFile,那么还要参考System.IO.Compression.FileSystem。【参考方案3】:

最简单的方法是使用临时文件夹。

用于压缩:

    创建临时文件夹 将文件移动到文件夹 压缩文件夹 删除文件夹

解压:

    解压存档 将文件从临时文件夹移动到您的位置 删除临时文件夹

【讨论】:

感谢您的建议。对于任何好奇的人,我正在使用它来添加一个应用程序,该应用程序将 Lotus Notes 附件作为嵌入式对象移动到 MSWord 文件中,但是原生不支持两种古老的文件类型,因此使用了 zip 解决方案。 更像:先压缩然后解压缩... 好吗? GG【参考方案4】:

在 .NET 中,有很多方法可以解决单个文件的问题。如果您不想在那里学习所有内容,可以获取一个抽象库,例如 SharpZipLib(长期开源库)、sevenzipsharp(下面需要 7zip 库)或 DotNetZip。

【讨论】:

【参考方案5】:

只需使用以下代码压缩文件。

public void Compressfile()
        
             string fileName = "Text.txt";
             string sourcePath = @"C:\SMSDBBACKUP";
             DirectoryInfo di = new DirectoryInfo(sourcePath);
             foreach (FileInfo fi in di.GetFiles())
             
                 //for specific file 
                 if (fi.ToString() == fileName)
                 
                     Compress(fi);
                 
              
        

public static void Compress(FileInfo fi)
        
            // Get the stream of the source file.
            using (FileStream inFile = fi.OpenRead())
            
                // Prevent compressing hidden and 
                // already compressed files.
                if ((File.GetAttributes(fi.FullName)
                    & FileAttributes.Hidden)
                    != FileAttributes.Hidden & fi.Extension != ".gz")
                
                    // Create the compressed file.
                    using (FileStream outFile =
                                File.Create(fi.FullName + ".gz"))
                    
                        using (GZipStream Compress =
                            new GZipStream(outFile,
                            CompressionMode.Compress))
                        
                            // Copy the source file into 
                            // the compression stream.
                            inFile.CopyTo(Compress);

                            Console.WriteLine("Compressed 0 from 1 to 2 bytes.",
                                fi.Name, fi.Length.ToString(), outFile.Length.ToString());
                        
                    
                
            
        

    

【讨论】:

这是 GZIP,不是 ZIP

以上是关于使用 C# 压缩单个文件的主要内容,如果未能解决你的问题,请参考以下文章

SevenZipSharp - 如何使用 c# 将多个目录压缩成一个文件?

SharpZipLib : 将单个文件压缩为单个压缩文件

使用 Cygwin 压缩文件夹中的单个文件并压缩整个文件夹

通过 C# 减小 PDF 文档大小

从 NSIS 发送到压缩(压缩)文件夹

如何使用 Objective-C 解压缩/解压缩,包括单个文件检索