Home > OS >  Can I maintain directory structure when zipping file?
Can I maintain directory structure when zipping file?

Time:11-16

I'm attempting to zip up a handful of files but these files could exist in different directories. The zipping portion is working correctly but I cannot figure out how to get it to preserve the directory structure within the zip file.

Here's what I have so far:

public static void CreateZipFile(IEnumerable<FileInfo> files, string archiveName)
{
  using (var stream = File.OpenWrite(archiveName))
  using (var archive = new ZipArchive(stream, ZipArchiveMode.Create))
  {
    foreach (var item in files)
    {
      archive.CreateEntryFromFile(item.FullName, item.Name, CompressionLevel.Optimal);
    }
  }
}

Is this possible?

CodePudding user response:

@ErocM the link provided by @Flydog57 gives you exactly what you want. You are not exploiting the entryName argument correctly (the second argument in your case when calling CreateEntryFromFile).

Independently of which file you are adding to the archive (from same of different folders), you have to structure your archive using the entryName argument the C# api gives to you.

If your file's fullname is /tmp/myfile.txt, and you do archive.CreateEntryFromFile(item.FullName, item.Name), then the archive entry name will be myfile.txt. No folder created as the entry name doesn't contain folder structure in it's name.

However, if you call archive.CreateEntryFromFile(item.FullName, item.FullName), you will then have you file folder structure into the archive.

You can try with your function just changing item.Name into item.FullName.

Just be careful, on windows; if you path is C:\tmp\myfile.txt for instance, the archive will not be extractable correctly. You can then add some little code to remove C: from the full name of your files.

Some examples taking your implementation:

using System;
using System.IO;
using System.Collections.Generic;
using System.IO.Compression;

namespace ConsoleApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            FileInfo f1 = new FileInfo(@"/tmp/test1.txt");
            FileInfo f2 = new FileInfo(@"/tmp/testdir/test2.txt");

            List<FileInfo> files = new();
            files.Add(f1);
            files.Add(f2);

            CreateZipFile(files, @"/tmp/archive.zip");

        }

        public static void CreateZipFile(IEnumerable<FileInfo> files, string archiveName)
        {
            using (var stream = File.OpenWrite(archiveName))
            using (var archive = new ZipArchive(stream, ZipArchiveMode.Create))
            {
                foreach (var item in files)
                {
                    // Here for instance, I put all files in the input list in the same directory, without checking from where they are in the host file system.
                    archive.CreateEntryFromFile(item.FullName, $"mydir/{item.Name}", CompressionLevel.Optimal);

                    // Here, I am just using the actual full path of the file. Be careful on windows with the disk name prefix (C:, D:, etc...).
                    // archive.CreateEntryFromFile(item.FullName, item.FullName, CompressionLevel.Optimal);
                }
            }
        }
    }
  • Related