使用C#压缩单个文件

42
我正在使用.NET 4.5,如果我想要使用“CreateFromDirectory”压缩整个目录,则ZipFile类非常有效。但是,我只想压缩目录中的一个文件。我尝试指向特定文件(folder\data.txt),但那行不通。我考虑使用ZipArchive类,因为它具有“CreateEntryFromFile”方法,但似乎只允许将条目创建到现有文件中。
在不创建空zip文件(会有问题)然后再使用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;",它会抛出一个无效目录的错误。


但是那样做不起作用。什么没有起作用?你的代码在哪里? - L.B
指向特定文件的“CreateFromDirectory”无法工作。我已将Microsoft示例添加到原始问题中。 - user3362735
您可以使用ZipArchive类创建一个新的Zip归档文件,尽管它不是一个单行代码。请参见此处的答案了解如何操作。(如果这太麻烦了,您可以考虑使用更好的第三方ZIP处理库,例如DotNetZip - user2819245
2
或者你可以将文件移动到一个临时文件夹进行压缩,然后在删除后从同一临时文件夹中提取?最好的解决方案是获取一个更好的库。 - AlexanderBrevig
@elgonzo,谢谢你的建议,但我提到了我不能使用第三方解决方案。看起来被引用答案中的人们试图从头开始创建新文件并写入流,但我会尝试从那里找出一个解决方案。谢谢。 - user3362735
嗨@AlexanderBrevig,你介意建议这个作为答案吗?我会接受它。 - user3362735
5个回答

66

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

然后你可以将MemoryStream写入文件

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

8
这应该是被接受的解决方案。虽然AlexanderBrevig的解决方案可能有效,但是创建一个临时文件夹来制作zip文件涉及到很多不必要的额外步骤。John Koerner的解决方案更简单,但可以更简单。如果你用FileStream代替他的MemoryStream,就不需要第二步将MemoryStream写入磁盘。也许有速度或内存使用方面的优势我不知道,但如果ZIP文件是最终目标,则直接使用FileStream更好。 - Johnny Cee
3
请注意:在使用ZipArchive时,需要将System.IO.Compression引用添加到您的项目中,而不仅仅是System.IO.Compression.FileSystem - pagep

28

使用文件(或任何)流:

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 的引用。

更新

此外,请查看新的 dotnet API 文档,了解有关 ZipFileZipArchive 的信息。其中还包含一些示例。同时,还要注意可能需要引用 System.IO.Compression.FileSystem 才能使用 ZipFile

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


1
可能是一个愚蠢的问题...但是即使添加了dll引用,ZipArchiveMode也无法被识别为System.IO.Compression命名空间的一部分。我看到它有文档记录,但是VS2012似乎无法找到它(“当前上下文中不存在'ZipArchiveMode'的名称”)? - Softerware
6
请确保在文中加入对 System.IO.Compression 的引用。如果要使用 CreatEntryFromFile 函数,则还需要引用 System.IO.Compression.FileSystem。 - Atron Seige

10

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

压缩:

  1. 创建一个临时文件夹
  2. 将文件移动到文件夹中
  3. 压缩文件夹
  4. 删除文件夹

解压:

  1. 解压档案
  2. 将文件从临时文件夹移动到您的位置
  3. 删除临时文件夹

1
谢谢您的建议。对于任何感兴趣的人,我正在使用这个来增加一个应用程序,将Lotus Notes附件移动到MSWord文件中作为嵌入对象,但其中两个古老的文件类型不受本地支持,因此需要使用zip解决方案。 - user3362735
更像:先压缩再解压缩...行吗?GG - Yousha Aleayoub

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

-1
只需使用以下代码来压缩文件。
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的。 - Cocowalla

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接