Extrair arquivos de um arquivo Zip programaticamente usando C # e System.IO.Packaging

StackOverflow https://stackoverflow.com/questions/507751

  •  21-08-2019
  •  | 
  •  

Pergunta

Eu tenho um monte de ZIP arquivos que estão em necessidade desesperada de alguma reorganização hierárquica e extração. O que posso fazer, no momento, é criar a estrutura de diretório e mover os arquivos zip para o local adequado. O queijo mística que estou em falta é a parte que extrai os arquivos do arquivo ZIP.

Eu vi os artigos do MSDN sobre a classe ZipArchive e compreendê-los bem razoável. Também já vi os VBScript maneiras de extrair . Esta não é uma classe complexa assim extrair o material deve ser bastante simples. Na verdade, ele funciona "principalmente". Eu incluí meu código atual abaixo para referência.

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

O problema parece estar em algum lugar na GetParts (ou Get Tudo para que o assunto). Parece que o pacote, enquanto aberto, está vazio. Indo mais fundo os shows depurador que os shows particulares membro _zipArchive que ele realmente tem partes. Peças com os nomes certos e tudo. Por que a função GetParts não vai recuperá-los? I'ver tentou lançar o aberto a uma ZipArchive e isso não ajudou. Grrr.

Foi útil?

Solução

Se você está manipulando arquivos zip, você pode querer olhar para uma biblioteca de 3-parte para ajudá-lo.

Por exemplo, DotNetZip, que foi recentemente atualizado. A versão atual é agora v1.8. Aqui está um exemplo para criar um 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");
}

Aqui está um exemplo para Atualização um zip existente; você não precisa para extrair os arquivos para fazê-lo:

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

aqui está um exemplo que extrai entradas:

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

DotNetZip suporta caracteres multi-byte em nomes de arquivos, criptografia zip, encriptação AES, córregos, Unicode, arquivos auto-extraíveis. Também faz ZIP64, para comprimentos de arquivo superiores a 0xFFFFFFFF, ou para arquivos com mais de 65535 entradas.

livre. open source

obtê-lo em codeplex ou download direto de windows.net - CodePlex foi interrompido e arquivado

Outras dicas

A partir MSDN ,

Neste exemplo, a classe Package é usado (em oposição ao ZipPackage.) Tendo trabalhado com ambos, eu só vi flakiness acontecer quando há corrupção no arquivo zip. Não necessariamente corrupção que joga o extrator Windows ou Winzip, mas algo que os componentes de embalagens têm manuseio problemas.

Espero que isso ajude, talvez ele possa lhe fornecer uma alternativa para depurar o 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();
    }
}

De " ZipPackage Classe "(MSDN):

Embora os pacotes são armazenados como Zip arquivos * através da classe ZipPackage, todos Zip arquivos não são ZipPackages. A ZipPackage tem exigências especiais, tais como arquivo URI-compliant (parte) Nomes e um arquivo "[Content_Types] .xml" que define os tipos MIME para todos os arquivos contidos no pacote. A classe ZipPackage não pode ser usado para arquivos Zip arbitrários abertas que não estejam em conformidade com as Open Packaging Conventions padrão.

Para mais detalhes veja Seção 9.2 "Mapping a um ZIP Archive" dos "Open Packaging Conventions" ECMA internacionais 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,3MB)

* Você pode simplesmente adicionar ".zip" para a extensão de qualquer arquivo baseado em ZipPackage (.docx, .xlsx, .pptx, etc.) para abri-lo em seu utilitário favorito Zip.

Eu estava tendo exatamente o mesmo problema! Para obter os GetParts () para retornar algo, eu tive que adicionar o [Content_Types] arquivo .xml para a raiz do arquivo com um nó "Default" para cada extensão de arquivo incluído. Uma vez que eu adicionado este (apenas usando o Windows Explorer), o meu código era capaz de ler e extrair os conteúdos arquivados.

Mais informações sobre o [Content_Types] arquivo .xml pode ser encontrada aqui:

http://msdn.microsoft.com/en-us/magazine/ cc163372.aspx - Há um arquivo exemplo abaixo Figura 13 do artigo

.
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: este código usa o método Stream.CopyTo em .NET 4.0

Eu concordo withe Cheeso. System.IO.Packaging é estranho ao manusear arquivos zip genéricos, vendo como ele foi projetado para documentos Office Open XML. Eu sugiro usar DotNetZip ou SharpZipLib

(Esta é basicamente uma reformulação da esta resposta )

Acontece que System.IO.Packaging.ZipPackage não suporta PKZIP, é por isso que quando você abre um arquivo de "genérico" ZIP não "partes" são devolvidos. Esta classe suporta apenas algum sabor específico de arquivos zip (ver comentários na parte inferior da MSDN descrição ) usado entre outros como pacotes de serviços do Windows Azure de até SDK 1.6 - por isso, se você descompactar um pacote de serviços e, em seguida, coloque-o novamente usando digamos Info-ZIP Packer ele se tornará inválido.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top