19

I wish to know if there is any way to avoid to have a [Content_Types].xml file inside the zip file while using .net's ZipPackage class.

Kushal Waikar
  • 2,976
  • 5
  • 26
  • 31
  • whats your reason for using `ZipPackage`? If you wish to create a zip file out of existing documents, you are better off using `GZipStream` & related classes in the `System.IO.Compression` namespace. – shahkalpesh Sep 20 '10 at 06:41
  • 6
    @shahkalpesh: GZipStream is for single files only. – H H Sep 20 '10 at 09:33
  • @Henk: I wish to create a ".zip" file for a single document. Is it possible to create ".zip" file using GZipStream ? – Kushal Waikar Sep 20 '10 at 09:42
  • @Kushal: No, not if you want to read it with other Zip tools. – H H Sep 20 '10 at 09:56
  • 1
    .NET 4.5 added a ZipArchive class to do this (http://msdn.microsoft.com/en-us/library/system.io.compression.ziparchive%28v=vs.110%29.aspx) – Govert Jan 03 '14 at 20:01

6 Answers6

9

No.

Zip Packages are not (normal) Zip files. They must follow an imposed structure and contain that Content_Types.xml file in the root. ZipPackage = ZipArchive + Structure.

If you want to create (and especially if you want to read) normal Zip archives you will need an extra library, there is no support in the BCL.

See SharpZipLib (GPL) and DotNetZip

H H
  • 263,252
  • 30
  • 330
  • 514
  • What do you mean by "normal" ? Is it not possible to create a ".zip" file using whatever is there inside .net framework ? – Kushal Waikar Sep 20 '10 at 09:44
  • 1
    @Kushal: Package = Zip Archive + Structure. So you can read a Zip Package with WinZip, but you cannot read (all) Zip files with ZipPackage – H H Sep 20 '10 at 09:55
  • I just wish to zip a single file. But I am not able to get rid of .xml file which gets embedded with the package. – Kushal Waikar Sep 20 '10 at 10:05
  • 2
    The contents.xml is what makes it a package. – H H Sep 20 '10 at 10:12
5

If you don't call the .Flush() method, there will be no such file

Yiping
  • 971
  • 10
  • 31
  • 1
    This is an excellent answer to this question, and this technique worked for me. If you create your `ZipPackage` with a memory stream, add your parts, and then copy the stream before disposing the `ZipPackage` (which calls `.Flush()`) then the resulting zip file contains only your added parts and no "[Context_Types].xml". – Matt Klein Feb 05 '15 at 19:03
  • @DLeh Sorry what do you mean? This is exactly the method, to avoid the file been added to the zip file. – Yiping Feb 06 '15 at 01:50
  • @MattKlein Thanks. I found this by accident (I forgot to dispose). But it seems to be working. – Yiping Feb 06 '15 at 01:51
  • Flushes who? Package, MemoryStream etc? – Murilo Sep 10 '18 at 17:15
  • @MattKlein what if I need to add multiple files? I have to flush it before opening it for next file. – Imad Jan 05 '21 at 10:38
2

Yes you can create zip packages without the extra XML content file added

Inspired by this link: Using System.IO.Packaging to generate a ZIP file

Using above discovery mentioned by Yiping you can avoid the extra xml file added into the package. Save zip stream from memory stream to a physical zip file before zip archive is closed like this:

public static void AddFilesToZip(string zipFilename, List<String> filesToAdd)
{
    using (var memStream = new MemoryStream())
    {
        using (Package zip = System.IO.Packaging.Package.Open(memStream, FileMode.Create))
        {

            foreach (var fileToAdd in filesToAdd)
            {
                string destFilename = ".\\" + Path.GetFileName(fileToAdd);
                Uri uri = PackUriHelper.CreatePartUri(new Uri(destFilename, UriKind.Relative));

                //Existing parts not likely in fresh memory stream
                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);
                    }
                }
            }

            //The zip Package will add an XML content type file to memeory stream when it closes
            //so before it closes we save the memorystream to physical zip file.
            using (FileStream zipfilestream = new FileStream(zipFilename, FileMode.Create, FileAccess.Write))
            {
                memStream.Position = 0;
                CopyStream(memStream, zipfilestream);
            }

            // That's it. Zip file saved to file. Things added by package after this point will be to memory stream finally disposed.
        }
    }
}
evandrix
  • 6,041
  • 4
  • 27
  • 38
flodis
  • 1,123
  • 13
  • 9
  • Got this working, thanks. The important part is memStream.Position = 0; without this you will get an empty zip. – apc Jul 15 '16 at 09:47
  • 3
    Where `CopyStream` comes? I tested your code, but when I extract the content of the .zip, says that the .zip is damaged. – Mauricio Arias Olave Dec 13 '16 at 21:09
  • It works, but it will throw OutOfMemoryException on web environment if there's a lot of files. – Murilo Sep 10 '18 at 18:07
1

Man, this helped me a lot! You rock! I had to use this because my old framework (3.5). Only to complement, see below the implementation of the CopyStream function:

    private void CopyStream(Stream source, Stream target)
    {
        const int bufSize = 0x1000;
        byte[] buf = new byte[bufSize];
        int bytesRead = 0;
        while ((bytesRead = source.Read(buf, 0, bufSize)) > 0)
            target.Write(buf, 0, bytesRead);
    }
Rodolfo
  • 11
  • 1
0

You can also set private field _contentTypeHelper of System.IO.Packaging.Package to null ( using DynamicObject ).

GhostCat
  • 137,827
  • 25
  • 176
  • 248
unitay
  • 21
  • 4
0

Run this function when you finish packing your zip file:

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{}
        }
    }
Teemo
  • 211
  • 2
  • 6