49

階層的な再編成と抽出がどうしても必要な ZIP ファイルがたくさんあります。現在、私ができることは、ディレクトリ構造を作成し、zip ファイルを適切な場所に移動することです。私が見逃している神秘的なチーズは、ZIP アーカイブからファイルを抽出する部分です。

私はクラスに関する MSDN の記事を見て、ZipArchiveそれらを十分に理解しています。を抽出する VBScript の方法も見てきました。これは複雑なクラスではないため、抽出は非常に簡単です。実際、それは「ほとんど」機能します。参照用に現在のコードを以下に含めます。

 using (ZipPackage package = (ZipPackage)Package.Open(@"..\..\test.zip", FileMode.Open, FileAccess.Read))
 {
    PackagePartCollection packageParts = package.GetParts();
    foreach (PackageRelationship relation in packageParts)
    {
       //Do Stuff but never gets here since packageParts is empty.
    }
 }

問題はどこかにあるようですGetParts(またはそのことについては Get Anything )。パッケージが開いている間は空のようです。デバッガーをさらに掘り下げると、プライベート メンバー _zipArchive が実際にパーツを持っていることが示されます。正しい名前のパーツとすべて。GetParts関数がそれらを取得しないのはなぜですか? オープンを ZipArchive にキャストしようとしましたが、役に立ちませんでした。うーん。

4

6 に答える 6

47

ZIP ファイルを操作している場合は、サードパーティのライブラリを調べてください。

たとえば、最近更新された DotNetZip です。現在のバージョンは v1.8 です。zip を作成する例を次に示します。

using (ZipFile zip = new ZipFile())
{
  zip.AddFile("c:\\photos\\personal\\7440-N49th.png");
  zip.AddFile("c:\\Desktop\\2005_Annual_Report.pdf");
  zip.AddFile("ReadMe.txt");

  zip.Save("Archive.zip");
}

既存の zipを更新する例を次に示します。ファイルを抽出する必要はありません。

using (ZipFile zip = ZipFile.Read("ExistingArchive.zip"))
{
  // 1. remove an entry, given the name
  zip.RemoveEntry("README.txt");

  // 2. Update an existing entry, with content from the filesystem
  zip.UpdateItem("Portfolio.doc");

  // 3. modify the filename of an existing entry 
  // (rename it and move it to a sub directory)
  ZipEntry e = zip["Table1.jpg"];
  e.FileName = "images/Figure1.jpg";

  // 4. insert or modify the comment on the zip archive
  zip.Comment = "This zip archive was updated " + System.DateTime.ToString("G"); 

  // 5. finally, save the modified archive
  zip.Save();
}

エントリを抽出する例を次に示します。

using (ZipFile zip = ZipFile.Read("ExistingZipFile.zip"))
{
  foreach (ZipEntry e in zip)
  {
    e.Extract(TargetDirectory, true);  // true => overwrite existing files
  }
}

DotNetZip は、ファイル名、Zip 暗号化、AES 暗号化、ストリーム、Unicode、自己解凍アーカイブでマルチバイト文字をサポートします。ファイル長が 0xFFFFFFFF を超える場合、または 65535 エントリを超えるアーカイブの場合は、ZIP64 も実行します。

自由。オープンソース

codeplexで入手する か、windows.net から直接ダウンロードしてください- CodePlex は廃止され、アーカイブされています

于 2009-02-10T06:09:38.180 に答える
46

MSDNから、

このサンプルでは、​​Package クラスが (ZipPackage とは対照的に) 使用されています。両方を使用してきましたが、zip ファイルに破損がある場合にのみフレークが発生するのを見てきました。Windows エクストラクタまたは Winzip をスローする破損とは限りませんが、パッケージング コンポーネントの処理に問題があるものです。

これがお役に立てば幸いです。おそらく、問題をデバッグする代わりの方法が提供される可能性があります。

using System;
using System.IO;
using System.IO.Packaging;
using System.Text;

class ExtractPackagedImages
{
    static void Main(string[] paths)
    {
        foreach (string path in paths)
        {
            using (Package package = Package.Open(
                path, FileMode.Open, FileAccess.Read))
            {
                DirectoryInfo dir = Directory.CreateDirectory(path + " Images");
                foreach (PackagePart part in package.GetParts())
                {
                    if (part.ContentType.ToLowerInvariant().StartsWith("image/"))
                    {
                        string target = Path.Combine(
                            dir.FullName, CreateFilenameFromUri(part.Uri));
                        using (Stream source = part.GetStream(
                            FileMode.Open, FileAccess.Read))
                        using (Stream destination = File.OpenWrite(target))
                        {
                            byte[] buffer = new byte[0x1000];
                            int read;
                            while ((read = source.Read(buffer, 0, buffer.Length)) > 0)
                            {
                                destination.Write(buffer, 0, read);
                            }
                        }
                        Console.WriteLine("Extracted {0}", target);
                    }
                }
            }
        }
        Console.WriteLine("Done");
    }

    private static string CreateFilenameFromUri(Uri uri)
    {
        char [] invalidChars = Path.GetInvalidFileNameChars();
        StringBuilder sb = new StringBuilder(uri.OriginalString.Length);
        foreach (char c in uri.OriginalString)
        {
            sb.Append(Array.IndexOf(invalidChars, c) < 0 ? c : '_');
        }
        return sb.ToString();
    }
}
于 2009-02-03T17:21:09.963 に答える
31

ZipPackage クラス」(MSDN) から:

パッケージは ZipPackage クラスを通じて Zip ファイル* として保存されますが、すべての Zip ファイルは ZipPackage ではありません。ZipPackage には、URI 準拠のファイル (パーツ) 名や、パッケージに含まれるすべてのファイルの MIME タイプを定義する「[Content_Types].xml」ファイルなど、特別な要件があります。ZipPackage クラスを使用して、Open Packaging Conventions 標準に準拠していない任意の Zip ファイルを開くことはできません。

詳細については、ECMA International の「Open Packaging Conventions」標準のセクション 9.2「Mapping to a ZIP Archive」を参照してください。 20Part%202%20(DOCX).zip (342Kb) またはhttp://www.ecma-international.org/publications/files/ECMA-ST/Office%20Open%20XML%20Part%202%20(PDF).zip (1.3Mb)

*ZipPackage ベースのファイル (.docx、.xlsx、.pptx など) の拡張子に「.zip」を追加するだけで、お気に入りの Zip ユーティリティで開くことができます。

于 2009-02-03T17:34:15.473 に答える
13

私はまったく同じ問題を抱えていました!GetParts() メソッドが何かを返すようにするには、[Content_Types].xml ファイルをアーカイブのルートに追加し、ファイル拡張子ごとに「デフォルト」ノードを追加する必要がありました。これを (Windows エクスプローラーを使用して) 追加すると、コードはアーカイブされたコンテンツを読み取って抽出することができました。

[Content_Types].xml ファイルの詳細については、次の場所を参照してください。

http://msdn.microsoft.com/en-us/magazine/cc163372.aspx - 記事の図 13 の下にサンプル ファイルがあります。

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)) 
        { 
            FileStream targetFile = File.OpenWrite(target);
            source.CopyTo(targetFile);
            targetFile.Close();
        } 
    } 
} 

注: このコードは、.NET 4.0 の Stream.CopyTo メソッドを使用します。

于 2012-04-09T12:01:35.523 に答える
6

Cheesoに同意します。System.IO.Packagingは、Office Open XMLドキュメント用に設計されているため、一般的なzipファイルを処理するときに扱いにくいものです。DotNetZipまたはSharpZipLibの使用をお勧めします

于 2009-02-10T06:51:13.680 に答える
2

(This is basically a rephrasing of this answer)

Turns out that System.IO.Packaging.ZipPackage doesn't support PKZIP, that's why when you open a "generic" ZIP file no "parts" are returned. This class only supports some specific flavor of ZIP files (see comments at the bottom of MSDN description) used among other as Windows Azure service packages up to SDK 1.6 - that's why if you unpack a service package and then repack it using say Info-ZIP packer it will become invalid.

于 2012-08-21T08:34:49.190 に答える