49 votes

Extraction de fichiers à partir d'une archive Zip par programme à l'aide de C # et System.IO.Packaging

J'ai un tas de fichiers ZIP qui sont dans le besoin désespéré d'une réorganisation hiérarchique et d'extraction. Ce que je peux faire, actuellement, c'est de créer la structure de répertoire et de déplacer les fichiers zip à l'emplacement approprié. La mystique de fromage que je suis en manque, c'est la partie qui extrait les fichiers de l'archive ZIP.

J'ai vu les articles MSDN sur l' ZipArchive de la classe et de les comprendre raisonnable. J'ai également vu le VBScript façons d'extraire. Ce n'est pas un complexe de classe, pour l'extraction de truc devrait être assez simple. En fait, il fonctionne "la plupart". J'ai inclus dans mon code ci-dessous pour référence.

 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.
    }
 }

Le problème semble être quelque part en GetParts (ou s'*Rien* d'ailleurs). Il semble que le colis, tout est vide. Creuser plus profondément le débogueur montre que le membre privé _zipArchive montre qu'il a effectivement pièces. Pièces avec le droit des noms et tout et tout. Pourquoi ne pas l' GetParts fonction de les récupérer? Je'ver tenté le casting de l'ouvrir à un ZipArchive et qui n'a pas aidé. Grrr.

47voto

Cheeso Points 87022

Si vous manipulez des fichiers ZIP, vous pouvez regarder dans une 3e partie de la bibliothèque pour vous aider.

Par exemple, DotNetZip, qui a été récemment mis à jour. L'actuelle version est v1.8. Voici un exemple pour créer un 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");
}

Voici un exemple de mise à jour d'un zip existant, vous n'avez pas besoin d'extraire les fichiers:

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

voici un exemple qui extrait les entrées:

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

DotNetZip supporte le multi-octets caractères dans les noms de fichiers Zip cryptage, le cryptage AES, des ruisseaux, de l'Unicode, des archives auto-extractibles. Aussi ne ZIP64, pour le fichier de longueurs supérieures à la valeur 0xFFFFFFFF, ou pour les archives de plus de 65 535 entrées.

gratuit. open source

l'obtenir à codeplex

46voto

jro Points 5120

À partir de MSDN,

Dans cet exemple, la classe de Package est utilisé (par opposition à la ZipPackage.) Ayant travaillé avec les deux, je n'ai vu que feuilletage se produire quand il y a de la corruption dans le fichier zip. Pas nécessairement la corruption qui lance le Windows extracteur ou Winzip, mais quelque chose que l'Emballage de composants ont de la difficulté à gérer.

Espérons que cette aide, peut-être il peut vous fournir une solution de rechange pour le débogage de la question.

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

31voto

Luke Points 2171

De "ZipPackage Classe" (en anglais):

Alors que les Paquets sont stockés sous forme de fichiers Zip* par le biais de la ZipPackage classe, tous les fichiers Zip ne sont pas ZipPackages. Un ZipPackage a des besoins spéciaux tels que l'URI-de fichier compatible (une partie) des noms et un "[Content_Types].xml" fichier qui définit les types MIME pour tous les fichiers contenus dans le Package. Le ZipPackage classe ne peut pas être utilisé pour ouvrir arbitraire des fichiers Zip qui ne sont pas conformes à l'Open Packaging Conventions standard.

Pour de plus amples détails, voir la Section 9.2 "Cartographie d'une Archive ZIP" de l'ECMA International "Open Packaging Conventions" standard, http://www.ecma-international.org/publications/files/ECMA-ST/Office%20Open%20XML%20Part%202%20(DOCX).zip (342Kb) ou http://www.ecma-international.org/publications/files/ECMA-ST/Office%20Open%20XML%20Part%202%20(PDF).zip (1.3 Mo)

*Vous pouvez simplement ajouter ".zip" à la prolongation de la ZipPackage à base de fichier (.docx, .xlsx, .pptx, etc.) pour l'ouvrir dans votre logiciel préféré utilitaire Zip.

13voto

Joshua Points 2094

J'ai eu exactement le même problème! Pour obtenir le GetParts() la méthode de retourner quelque chose, j'ai dû ajouter de la [Content_Types].fichier xml à la racine de l'archive avec un "Défaut" nœud pour chaque extension de fichier inclus. Une fois que j'ai ajouté (juste à l'aide de l'Explorateur Windows), mon code a été en mesure de lire et d'extraire l'archive de contenu.

Plus d'informations sur le [Content_Types].fichier xml peut être trouvé ici:

http://msdn.microsoft.com/en-us/magazine/cc163372.aspx - Il y a un fichier de l'exemple ci-dessous Figure 13 de l'article.

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

Remarque: ce code utilise le Flux.Méthode CopyTo .NET 4.0

6voto

Rad Points 6308

Je suis d'accord avec Cheeso. System.IO.Packaging est gênant lors de la gestion de fichiers zip génériques, car il a été conçu pour les documents Office Open XML. Je suggérerais d'utiliser DotNetZip ou SharpZipLib

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X