How to compress a directory with the built in .net

2019-02-19 19:57发布

问题:

Using the System.IO.Compression namespaces classes GZIPStream and DeflateStream I successfully can compress and decompress individual files. However, if I pass a directoryname as target for compression I get a security exception. Do I have to (recursively) enumerate all files and subdirectories to be able to compress a directory?

(Probably dotnetzip from codeplex will handle this better, but that is not what I am after now).

回答1:

When you use GZipStream etc, you are compressing a stream; not a file. GZip has no file header information, so there is no sensible way of packing multiple files. For that you need something like .zip; #ziplib will do the job, but you still (IIRC) need to feed it each file manually.



回答2:

The System.IO.Compression classes provide no way to manage multifile archives. You need to do some work on your own to create a file format that track what is in your archive. This article might help you get started:

How to compress folders and multiple files with GZipStream and C# (System.IO.Compression.GZipStream)

However if you're after a format that you can exchange files with users who only have WinZip or WinRAR then you're better off looking into something like SharpZipLib.



回答3:

The classes in System.IO.Compression will only handle streams, yes. You'll have to do file handling yourself. You could, I suppose, use SharpZipLib or similar to tar the files, then compress the resulting tar file. Simple as (untested):

using (Stream out = new FileStream("out.tar", FileMode.CreateNew))
{
    TarArchive archive = TarArchive.CreateOutputTarArchive(outStream
                                    , TarBuffer.DefaultBlockFactor);
    foreach (string name in fileNames)
    {
        TarEntry entry = TarEntry.CreateEntryFromFile(name);
        archive.WriteEntry(entry, true);
    }
}


回答4:

People have mentioned this before, the built in .Net classes are good a compressing streams not directory structures.

They also mentioned that sharpziplib etc.. are good libraries to use, I agree. They offer Zip and Tar implementaions which are useful.

But... if your hands are tied and you can not use these libs, keep in mind that the tar format is really simple. Implementing: Stream ToTar(string path) is a fairly simple and straight forward task (unlike implementing compression algorithms)



回答5:

This compresses .\in contents to .\out.zip with Powershell and System.IO.Packaging.ZipPackage following the example here

$zipArchive = $pwd.path + "\out.zip"
[System.Reflection.Assembly]::Load("WindowsBase,Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")
$ZipPackage=[System.IO.Packaging.ZipPackage]::Open($zipArchive, [System.IO.FileMode]"OpenOrCreate", [System.IO.FileAccess]"ReadWrite")
$in = gci .\in | select -expand fullName
[array]$files = $in -replace "C:","" -replace "\\","/"
ForEach ($file In $files) {
   $partName=New-Object System.Uri($file, [System.UriKind]"Relative")
   $part=$ZipPackage.CreatePart($partName, "application/zip", [System.IO.Packaging.CompressionOption]"Maximum")
   $bytes=[System.IO.File]::ReadAllBytes($file)
   $stream=$part.GetStream()
   $stream.Write($bytes, 0, $bytes.Length)
   $stream.Close()
                                                    }
$ZipPackage.Close()