2009-02-03 14 views
46

Ho un sacco di file ZIP che hanno un disperato bisogno di una riorganizzazione ed estrazione gerarchica. Quello che posso fare, attualmente, è creare la struttura delle directory e spostare i file zip nella posizione corretta. Il formaggio mistico che mi manca è la parte che estrae i file dall'archivio ZIP.Estrazione di file da un archivio Zip utilizzando C# e System.IO.Packaging

Ho visto gli articoli MSDN sulla classe ZipArchive e li ho capiti ragionevolmente bene. Ho anche visto lo VBScript ways to extract. Questa non è una classe complessa, quindi estrarre le cose dovrebbe essere piuttosto semplice. In effetti, funziona "per lo più". Ho incluso il mio codice attuale sotto per riferimento.

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

Il problema sembra essere da qualche parte nel GetParts (o Get Tutto per questo). Sembra che il pacchetto, mentre è aperto, sia vuoto. Scavando più in profondità il debugger mostra che il membro privato _zipArchive mostra che in realtà ha parti. Parti con i nomi giusti e tutto. Perché la funzione GetParts non li recupera? Ho provato a trasmettere l'open a ZipArchive e questo non ha aiutato. Grrr.

+1

FYI, Ho inviato una richiesta su MS Connect per aggiungere supporto per archivio ZIP generico. Puoi votare anche su https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=477393 –

risposta

45

Se si stanno manipolando file ZIP, si consiglia di cercare in una libreria di terze parti per aiutarvi.

Ad esempio, DotNetZip, che è stato aggiornato di recente. La versione attuale è ora v1.8.Ecco un esempio per creare una cerniera:

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

Ecco un esempio di aggiornamento zip esistente; non è necessario per estrarre i file per farlo:

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

Ecco un esempio che estrae le voci:

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

DotNetZip supporta caratteri multi-byte nei nomi dei file, zip crittografia, crittografia AES, ruscelli , Unicode, archivi autoestraenti. Anche ZIP64, per lunghezze di file maggiori di 0xFFFFFFFF, o per archivi con più di 65535 voci.

gratuito. open source

farlo a codeplex

+1

cheeso, sono d'accordo con te ,,, ma non sono in grado di costruire il codice che ho scaricato frm codeplex .. si prega di dire come costruire .. se io costruisco la soluzione principale il suo lancio di lotti o errori .. non so come build – Naruto

+4

perchè lo stai costruendo? C'è un binario. Scarica la DLL. – Cheeso

+1

Perché consigliare una libreria di terze parti, non dovrebbe essere sufficiente lo spazio dei nomi 'System.IO.Packaging'? O è il tuo ultimo paragrafo che descrive in dettaglio cosa include la funzionalità integrata di .NET framework Zip ** e non **? –

44

Da MSDN,

In questo esempio, la classe pacchetto viene utilizzata (in contrapposizione al ZipPackage.) Avendo lavorato con entrambi, ho visto solo flakiness accadere quando c'è la corruzione nel file zip. Non necessariamente corruzione che getta l'estrattore di Windows o Winzip, ma qualcosa che i componenti di Packaging hanno problemi di gestione.

Spero che questo aiuti, forse può fornire un'alternativa al debug del problema.

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

Guardando quel codice, ho appena tirato su le mie scarpe. PackagePartCollection? PartRelationship? PackagePart? URI parte? ToLowerInvariant? Tutto quello che volevo era un file ZIP ... – Cheeso

+2

Sì, quella sarebbe stata la parte che gli sviluppatori di OpenPackage sembravano dimenticare. Lavorare con OpenPackage significa molto di più lavorare con i componenti virtuali, al contrario della rappresentazione fisica. – jro

+15

Questa è l'unica risposta che risponde alla vera domanda di come uso X per fare Y, ha codice e tutto, non va in tangente e mostra come usare Z per fare Y, ed è il minimo voti? Andiamo gente. – a7drew

29

Da "ZipPackage Class" (MSDN):

Mentre i pacchetti vengono memorizzati come file Zip * attraverso la classe ZipPackage, tutti i file Zip non sono ZipPackages. Uno ZipPackage ha requisiti speciali come nomi di file (parte) conformi agli URI e un file "[Content_Types] .xml" che definisce i tipi MIME per tutti i file contenuti nel pacchetto. La classe ZipPackage non può essere utilizzata per aprire file Zip arbitary non conformi allo standard Open Packaging Conventions.

Per ulteriori dettagli vedere paragrafo 9.2 "Mappatura ad un archivio ZIP" dello standard ECMA Internazionale "di Open Packaging Conventions", http://www.ecma-international.org/publications/files/ECMA-ST/Office%20Open%20XML%20Part%202%20(DOCX).zip (342Kb) o http://www.ecma-international.org/publications/files/ECMA-ST/Office%20Open%20XML%20Part%202%20(PDF).zip (1.3Mb)

* Si può semplicemente aggiungere" .zip "all'estensione di qualsiasi file basato su ZipPackage (.docx, .xlsx, .pptx, ecc.) per aprirlo nella tua utility Zip preferita.

+0

Questo è utile, grazie! –

6

Sono d'accordo withe Cheeso. System.IO.Packaging è scomodo durante la gestione di file zip generici, visto che è stato progettato per i documenti Office Open XML. Io suggerirei di usare DotNetZip o

12

Stavo avendo lo stesso identico problema! Per ottenere il metodo GetParts() per restituire qualcosa, ho dovuto aggiungere il file .xml [Content_Types] alla radice dell'archivio con un nodo "Predefinito" per ogni estensione di file inclusa. Una volta aggiunto questo (usando solo Windows Explorer), il mio codice è stato in grado di leggere ed estrarre i contenuti archiviati.

Maggiori informazioni sul file XML [CONTENT_TYPES] può essere trovato qui:

http://msdn.microsoft.com/en-us/magazine/cc163372.aspx - V'è un esempio di file di seguito Figura 13 di questo articolo.

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

Nota: questo codice viene utilizzato il metodo Stream.CopyTo in .NET 4.0

+1

Grazie per aver risposto alla domanda nel modo in cui è stato chiesto! – shytikov

1

(Questo è fondamentalmente un riformulazione di this answer)

scopre che System.IO.Packaging.ZipPackage non supporta PKZIP, ecco perché quando apri un file ZIP "generico" non vengono restituite "parti". Questa classe supporta solo alcuni aspetti specifici dei file ZIP (vedere i commenti nella parte inferiore di MSDN description) utilizzati tra l'altro come pacchetti di servizi di Windows Azure fino a SDK 1.6: ecco perché se si disimballare un pacchetto di servizi e quindi reimballare usando say Info-ZIP packer diventerà non valido.

Problemi correlati