Üçüncü taraf API'ları kullanmadan bir dosyayı C # 'da ZIP olarak nasıl ekleyebilirim?


175

Eminim bu bir kopya değil, bu yüzden sadece bir dakika benimle ayı.

Herhangi bir üçüncü taraf kitaplığı kullanmadan bir dosyayı (C #) ZIP olarak programlayabilirim (Windows'ta)? Ben yerel bir pencere ya da böyle bir şeye ihtiyacım var; Bir süreci başlatma fikrinden gerçekten hoşlanmıyorum, ama kesinlikle yapmak zorunda kalırsam. Bir PInovke çağrısı çok daha iyi olurdu.

Başarısız olursa, gerçekten neyi başarmaya çalıştığımı size söyleyeyim: Bir kullanıcının tek bir istekte bir belge koleksiyonu indirmesine izin verme yeteneğine ihtiyacım var. Bunu nasıl başaracağınıza dair bir fikrin var mı?



1
@Chesso: Evet, bir ASPX sayfasından.
Esteban Araya

1
Birkaç hafta önce aynı şeyi ararken bu örneği yararlı buldum: syntaxwarriors.com/2012/…
JensB

2
4.5 Framework kullanıyorsanız, şimdi ZipArchive ve ZipFile sınıfları vardır.
GalacticJello

Herkes DotNetZip kullandı ??
Hot Licks

Yanıtlar:


85

.NET 3.5 mi kullanıyorsunuz? Sen kullanabilirsiniz ZipPackagesınıfını ve ilgili sınıfları. Eklediğiniz her dosya için bir MIME türü istediği için bir dosya listesini sıkıştırmaktan daha fazlası. Ne istersen yapabilir.

Şu anda bu dosyaları, ilgili birkaç dosyayı indirmek için tek bir dosyaya arşivlemek için benzer bir sorun için kullanıyorum. İndirme dosyasını masaüstü uygulamamızla ilişkilendirmek için bir dosya uzantısı kullanıyoruz. Karşılaştığımız küçük bir sorun, zip dosyalarını oluşturmak için sadece 7-zip gibi bir üçüncü taraf aracı kullanmanın mümkün olmamasıydı, çünkü istemci tarafı kodu açamıyor - ZipPackage, içerik türünü açıklayan gizli bir dosya ekliyor her bileşen dosyasını içerir ve bu içerik türü dosyası eksikse bir zip dosyasını açamaz.


1
Oh SO, seni nasıl seviyorum! Teşekkürler Brian; yuo sadece bize bir sürü baş ağrısı ve bazı $$$ kurtardı.
Esteban Araya

6
Bunun her zaman tersine çalışmadığını unutmayın. Bazı Zip dosyaları ZipPackage sınıfını kullanarak rehidrasyon yapmaz. ZipPackage ile yapılan dosyalar iyi olmalısınız.
Craig

ZipPackage'ın mevcut sıkıştırılmış bir pakete eklenemeyeceğini unutmayın.
ΩmegaMan

İç çek: "System.IO" ad alanında "Ambalaj türü" veya ad alanı yok.
Hot Licks

2
(Yukarıdaki "iç çekişe" yanıt verin: "Başvurular" ı açın ve (mantıksal olarak yeterli) "WindowsBase" ekleyin.)
Hot Licks

307

Herhangi bir üçüncü taraf kitaplığı kullanmadan bir dosyayı (C #) ZIP olarak programlayabilirim (Windows'ta)?

4.5+ Framework kullanıyorsanız, artık ZipArchive ve ZipFile sınıfları vardır.

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

Aşağıdakilere referans eklemeniz gerekir:

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

.NET Core hedefleme net46 için,

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

Örnek project.json:

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

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

.NET Core 2.0 için, sadece basit bir deyim eklemek yeterlidir:

  • System.IO.Compression kullanarak;

4
Bu nasıl daha fazla oy almamış? Tek doğrudan cevap bu.
Matt Cashatt

12
Çünkü soru beş yaşında, oysa bu cevap sadece iki aylık. Derp :-P
Heliac

3
@heliac hala Stackoverflow thingie bir soru olmalı ve depo cevaplar ve ruhunda en iyi cevap shoudl üstte olmalı ... (lanet olsun, bunun işe yaramadığını biliyordum)
Offler

5
Kimseye yardım etmesi durumunda ikinci argüman dosya girdisidir. Bu, unzip klasörüne göre dosyanın ayıklanacağı yoldur. Windows 7'de, dosya girişi tam bir yolsa, örneğin @ "D: \ Temp \ file1.pdf" olursa, yerel Windows ayıklayıcının başarısız olduğunu buldum. Directory.GetFiles () öğesinden kaynaklanan dosya adlarını kullanırsanız bu sorunla karşılaşabilirsiniz. Dosya giriş argümanı için Path.GetFileName () kullanarak dosya adını ayıklamak en iyisidir.
Manish

2
4.5.2 'de bulamıyor gibi görünüyor?
user3791372

11

Aynı durumdaydım, üçüncü taraf bir kütüphane yerine .NET istemiştim. Yukarıda belirtilen başka bir poster gibi, sadece (.NET 3.5'te tanıtılan) ZipPackage sınıfını kullanmak yeterli değildir. ZipPackage'ın çalışması için arşive dahil edilmesi gereken ek bir dosya var. Bu dosya eklenirse, ortaya çıkan ZIP paketi doğrudan Windows Gezgini'nden açılabilir - sorun yok.

Tek yapmanız gereken [Content_Types] .xml dosyasını, eklemek istediğiniz her dosya uzantısı için "Varsayılan" düğümü ile arşiv köküne eklemektir. Eklendikten sonra, pakete Windows Gezgini'nden göz atabilirim veya içeriğini programlı olarak açıp okuyabilirim.

[Content_Types] .xml dosyası hakkında daha fazla bilgiyi şu adreste bulabilirsiniz: http://msdn.microsoft.com/en-us/magazine/cc163372.aspx

İşte [Content_Types] .xml (tam olarak adlandırılmalıdır) dosyasının bir örneği:

<?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>

Ve bir ZIP dosyası oluşturmak için 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)); 
            } 
        } 
    } 

Not:


12
Güzel bir örnek, ancak bir ZIP dosyası oluşturmuyor. Mevcut bir dosyayı açar.
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");
    }

Bir webapi içinde, bir HttpContext.Current.Request alırken sourceFileName nasıl alabilirim?
Olivertech

Daha fazla dosya sıkıştırılsın mı?
19'da Kiquenet

1

Simon McKenzie'nin bu soruya verdiği cevaba dayanarak , böyle bir çift yöntem kullanmanızı öneririm:

    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

Windows gibi görünüyor sadece yapalım belki bu ...

Maalesef, bir üçüncü taraf bileşenine gitmedikçe ayrı bir işleme başlayacağınızı sanmıyorum.


0

Bu 4 işlevi projenize ekleyin:

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

Ve bunları şöyle kullanın:

foreach (string f in UnitZipList)
{
    AddFileToZip(zipFile, f);
    System.IO.File.Delete(f);
}
Remove_Content_Types_FromZip(zipFile);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.