サードパーティのAPIを使用せずに、C#でファイルを圧縮するにはどうすればよいですか?


175

これは複製ではないので、少しお待ちください。

サードパーティのライブラリを使用せずに、プログラムで(C#)ファイルを(Windowsで)ZIP圧縮するにはどうすればよいですか?ネイティブのWindows呼び出しまたはそのようなものが必要です。プロセスを開始するという考えは本当に嫌いですが、絶対に必要な場合はそうするでしょう。PInovkeの呼び出しははるかに優れています。

それができない場合は、私が実際に達成しようとしていることをお話ししましょう。ユーザーが単一の要求でドキュメントのコレクションをダウンロードできるようにする機能が必要です。これを達成する方法に関するアイデアはありますか?



1
@チェソ:はい、ASPXページから。
エステバンアラヤ

1
私は数週間前に同じものを探していたとき、私は、この例の便利を見つけた:syntaxwarriors.com/2012/...
JensB

2
4.5フレームワークを使用している場合、ZipArchiveクラスとZipFileクラスがあります。
GalacticJello

誰もがDotNetZipを使用しましたか?
Hot Licks、2014

回答:


85

.NET 3.5を使用していますか?ZipPackageクラスと関連クラスを使用できます。追加するファイルごとにMIMEタイプが必要なため、ファイルリストを圧縮するだけではありません。それはあなたが望むことをするかもしれません。

私は現在、これらのクラスを使用して、いくつかの関連ファイルをダウンロード用の単一のファイルにアーカイブする同様の問題を抱えています。ファイル拡張子を使用して、ダウンロードファイルをデスクトップアプリに関連付けます。私たちが遭遇した小さな問題の1つは、クライアント側のコードで開くことができないため、7-zipなどのサードパーティツールを使用してzipファイルを作成するだけでは不可能であるということでした-ZipPackageは、各コンテンツファイル。コンテンツタイプファイルがない場合は、zipファイルを開くことができません。


1
ああ、なんて愛してるの!ブライアン、ありがとう。yuoは私たちに多くの頭痛の種といくつかの$$$を節約しました。
エステバンアラヤ

6
これは常に逆に機能するとは限らないことに注意してください。一部のZipファイルは、ZipPackageクラスを使用して再水和しません。ZipPackageで作成されたファイルは、問題ないはずです。
クレイグ、

ZipPackageは、既存の圧縮パッケージに追加できないことに注意してください。
ΩmegaMan

ため息:System.IO 『『名前空間に存在しない』パッケージ化「型または名前空間』。
ホット・リックス

2
(上記の「ため息」に答える:「参照」を開き、(非論理的に十分)「WindowsBase」を追加します。)
Hot Licks

307

サードパーティのライブラリを使用せずに、プログラムで(C#)ファイルを(Windowsで)ZIP圧縮するにはどうすればよいですか?

4.5+フレームワークを使用している場合は、今そこにあるZIPARCHIVEZIPファイルのクラス。

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

以下に参照を追加する必要があります。

  • System.IO.Compression
  • System.IO.Compression.FileSystem

net46をターゲットとする.NET Coreの場合、依存関係を追加する必要があります

  • System.IO.Compression
  • System.IO.Compression.ZipFile

project.jsonの例:

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

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

.NET Core 2.0の場合、必要なのは単純なusingステートメントを追加することだけです。

  • System.IO.Compressionを使用します。

4
どうしてこれ以上の賛成票を得られなかったのですか?それが唯一の直接的な答えです。
Matt Cashatt 14年

12
質問は5年前のものですが、この答えは2か月前のものだからです。Derp :-P
Heliac

3
@heliacまだのStackOverflowのthingieは、質問と回答のリポジトリであるべきと精神に最良の答えが上になるshoudl ...(いまいましい、私はこの仕事をしません知っていた)
Offler

5
誰かを助けるために、2番目の引数はファイルエントリです。これは、unzipフォルダーを基準にしてファイルが抽出されるパスです。Windows 7では、ファイルエントリがフルパス(@ "D:\ Temp \ file1.pdf"など)の場合、ネイティブのWindows抽出プログラムが失敗することがわかりました。Directory.GetFiles()の結果のファイル名を単に使用すると、この問題が発生する可能性があります。ファイルエントリの引数にPath.GetFileName()を使用してファイル名を抽出することをお勧めします。
マニッシュ、2014

2
4.5.2でこれを見つけることができないようです。
user3791372 2016年

11

私も同じ状況で、サードパーティのライブラリではなく.NETを使用したいと考えていました。上記の別のポスターとして、ZipPackageクラス(.NET 3.5で導入)を使用するだけでは十分ではありません。ZipPackageが機能するためには、アーカイブに追加する必要がある追加のファイルがあります。このファイルを追加すると、結果のZIPパッケージをWindowsエクスプローラーから直接開くことができます-問題ありません。

あなたがしなければならないすべてはあなたが含めたいすべてのファイル拡張子のための「デフォルト」ノードでアーカイブのルートに[Content_Types] .xmlファイルを追加することです。追加したら、Windowsエクスプローラーからパッケージを参照するか、プログラムで解凍して内容を読み取ることができます。

[Content_Types] .xmlファイルの詳細については、http//msdn.microsoft.com/en-us/magazine/cc163372.aspxを参照してください。

[Content_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)); 
            } 
        } 
    } 

注意:


12
素晴らしいサンプルですが、ZIPファイルは作成されません。既存のファイルを解凍します。
Matt Varblow、

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

Webapi内でHttpContext.Current.Requestを受け取っているときに、sourceFileNameを取得するにはどうすればよいですか?
Olivertech 2018

複数のファイルを圧縮しますか?
Kiquenet

1

この質問に対するサイモンマッケンジーの回答基づいて、次のような2つの方法を使用することをお勧めします。

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


0

次の4つの関数をプロジェクトに追加します。

        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);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.