42

I am using .NET 4.5, and the ZipFile class works great if I am trying to zip up an entire directory with "CreateFromDirectory". However, I only want to zip up one file in the directory. I tried pointing to a specific file (folder\data.txt), but that doesn't work. I considered the ZipArchive class since it has a "CreateEntryFromFile" method, but it seems this only allows you to create an entry into an existing file.

Is there no way to simply zip up one file without creating an empty zipfile (which has its issues) and then using the ZipArchiveExtension's "CreateEntryFromFile" method?

**This is also assuming I am working on a company program which cannot use third-party add-ons at the moment.

example from:http://msdn.microsoft.com/en-us/library/ms404280%28v=vs.110%29.aspx

        string startPath = @"c:\example\start";
        string zipPath = @"c:\example\result.zip";
        string extractPath = @"c:\example\extract";

        ZipFile.CreateFromDirectory(startPath, zipPath);

        ZipFile.ExtractToDirectory(zipPath, extractPath);

But if startPath were to be @"c:\example\start\myFile.txt;", it would throw an error that the directory is invalid.

  • `but that doesn't work` What doesn't work? where is your code? – L.B Jul 30 '14 at 16:32
  • Pointing to a specific file doesn't work with "CreateFromDirectory". I added the microsoft example to the original question. –  Jul 30 '14 at 16:35
  • You can create a new Zip archive using ZipArchive class, altough it is not exactly an one-liner. See the [answer here](http://stackoverflow.com/a/17939367/2819245) for how to do it. (If this is too cumbersome, you might think about using a better 3rd-party library for ZIP handling, such as [DotNetZip](https://dotnetzip.codeplex.com/)) –  Jul 30 '14 at 16:39
  • 2
    Or you could just move the file to a temporary folder for zipping, and extrat to the same temp folder after its deleted? Best solution is to get a better library though. – AlexanderBrevig Jul 30 '14 at 16:47
  • @elgonzo I mentioned that I cannot use 3rd-party solutions, but thanks for the suggestion. It seems like the people in the referenced answer were trying to create new files from scratch and write to streams, but I will try to work out a solution from there. THank you. –  Jul 30 '14 at 16:50
  • Hi @AlexanderBrevig, would you mind suggesting this as an answer? I will accept it. –  Jul 30 '14 at 18:11

5 Answers5

66

Use the CreateEntryFromFile off a an archive and use a file or memory stream:

Using a filestream if you are fine creating the zip file and then adding to it:

using (FileStream fs = new FileStream(@"C:\Temp\output.zip",FileMode.Create))
using (ZipArchive arch = new ZipArchive(fs, ZipArchiveMode.Create))
{
    arch.CreateEntryFromFile(@"C:\Temp\data.xml", "data.xml");
}

Or if you need to do everything in memory and write the file once it is done, use a memory stream:

using (MemoryStream ms = new MemoryStream())
using (ZipArchive arch = new ZipArchive(ms, ZipArchiveMode.Create))
{
    arch.CreateEntryFromFile(@"C:\Temp\data.xml", "data.xml");
}

Then you can write the MemoryStream to a file.

using (FileStream file = new FileStream("file.bin", FileMode.Create, System.IO.FileAccess.Write)) {
   byte[] bytes = new byte[ms.Length];
   ms.Read(bytes, 0, (int)ms.Length);
   file.Write(bytes, 0, bytes.Length);
   ms.Close();
}
Community
  • 1
  • 1
John Koerner
  • 37,428
  • 8
  • 84
  • 134
  • 8
    This should be the accepted solution. While AlexanderBrevig's solution may work, creating a folder temporarily to make a zip file involves a lot of extra steps that aren't necessary. John Koerner's solution is simpler, but could be even simpler. If you substitute a FileStream in place of his MemoryStream, you don't need the second step of writing the MemoryStream to disk. Perhaps there is a speed or memory usage advantage that I am not aware of, but going directly to a FileStream directly is better if a ZIP file is the ultimate goal. – Johnny Cee Oct 05 '16 at 01:12
  • 3
    FYI: When using you ZipArchive need to add `System.IO.Compression` reference to your project. Not only `System.IO.Compression.FileSystem`. – pagep Jan 04 '17 at 12:46
28

Using file (or any) stream:

using (var zip = ZipFile.Open("file.zip", ZipArchiveMode.Create))
{
    var entry = zip.CreateEntry("file.txt");
    entry.LastWriteTime = DateTimeOffset.Now;

    using (var stream= File.OpenRead(@"c:\path\to\file.txt"))
    using (var entryStream = entry.Open())
        stream.CopyTo(entryStream);
}

or briefer:

// reference System.IO.Compression
using (var zip = ZipFile.Open("file.zip", ZipArchiveMode.Create))
    zip.CreateEntryFromFile("file.txt", "file.txt");

make sure you add references to System.IO.Compression

Update

Also, check out the new dotnet API documentation for ZipFile and ZipArchive too. There are a few examples there. There is also a warning about referencing System.IO.Compression.FileSystem to use ZipFile.

To use the ZipFile class, you must reference the System.IO.Compression.FileSystem assembly in your project.

mtmk
  • 6,176
  • 27
  • 32
  • 1
    Might be a silly question....but ZipArchiveMode cannot be identified as part of the System.IO.Compression namespace even after adding the dll reference. I see it's documented, but VS2012 doesn't seem to be able to find it ("The name 'ZipArchiveMode' does not exist in the current context")? – Softerware Oct 23 '14 at 19:02
  • 6
    @AIng make sure you add references to System.IO.Compression. If you want to use CreatEntryFromFile, then also reference System.IO.Compression.FileSystem. – Atron Seige Jan 07 '15 at 11:38
10

The simplest way to get this working is to use a temporary folder.

FOR ZIPPING:

  1. Create a temp folder
  2. Move file to folder
  3. Zip folder
  4. Delete folder

FOR UNZIPPING:

  1. Unzip archive
  2. Move file from temp folder to your location
  3. Delete temp folder
AlexanderBrevig
  • 1,967
  • 12
  • 17
  • 1
    Thanks for the suggestion. For anyone curious, I'm using this to add to an application which moves Lotus Notes attachments into MSWord files as embedded objects, but two of the ancient file types aren't natively supported, hence the zip solution. –  Jul 31 '14 at 14:51
  • More like: do zip then unzip... OK? GG – Yousha Aleayoub Jun 05 '20 at 17:50
0

In .NET, there are quite a few ways to tackle the problem, for a single file. If you don't want to learn everything there, you can get an abstracted library, like SharpZipLib (long standing open source library), sevenzipsharp (requires 7zip libs underneath) or DotNetZip.

Gregory A Beamer
  • 16,870
  • 3
  • 25
  • 32
-1

just use following code for compressing a file.

public void Compressfile()
        {
             string fileName = "Text.txt";
             string sourcePath = @"C:\SMSDBBACKUP";
             DirectoryInfo di = new DirectoryInfo(sourcePath);
             foreach (FileInfo fi in di.GetFiles())
             {
                 //for specific file 
                 if (fi.ToString() == fileName)
                 {
                     Compress(fi);
                 }
             } 
        }

public static void Compress(FileInfo fi)
        {
            // Get the stream of the source file.
            using (FileStream inFile = fi.OpenRead())
            {
                // Prevent compressing hidden and 
                // already compressed files.
                if ((File.GetAttributes(fi.FullName)
                    & FileAttributes.Hidden)
                    != FileAttributes.Hidden & fi.Extension != ".gz")
                {
                    // Create the compressed file.
                    using (FileStream outFile =
                                File.Create(fi.FullName + ".gz"))
                    {
                        using (GZipStream Compress =
                            new GZipStream(outFile,
                            CompressionMode.Compress))
                        {
                            // Copy the source file into 
                            // the compression stream.
                            inFile.CopyTo(Compress);

                            Console.WriteLine("Compressed {0} from {1} to {2} bytes.",
                                fi.Name, fi.Length.ToString(), outFile.Length.ToString());
                        }
                    }
                }
            }
        }

    }
Jeetendra Negi
  • 443
  • 3
  • 3