Can't add empty folder to zip archive

277 Views Asked by At

I use C# .net 4.0. I create Zip archive using following:

    internal void compressZip(string folderPath)
    {
        if (!Directory.Exists(folderPath))
        {
            MessageBox.Show("Directory not exist: " + folderPath);
            return;
        }

        byte[] startBuffer = { 80, 75, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        File.WriteAllBytes(folderPath + ".zip", startBuffer);

        var shellAppType = Type.GetTypeFromProgID("Shell.Application");
        var oShell = Activator.CreateInstance(shellAppType);
        var sourceFolder = (Shell32.Folder)shellAppType.InvokeMember("NameSpace", System.Reflection.BindingFlags.InvokeMethod, null, oShell, new object[] { folderPath });
        var destinationFile = (Shell32.Folder)shellAppType.InvokeMember("NameSpace", System.Reflection.BindingFlags.InvokeMethod, null, oShell, new object[] { folderPath + ".zip" });
        destinationFile.CopyHere(sourceFolder.Items(), 4 | 16);
    }

But it have a problem when i try to compress empty folder. It's write "Can't add empty folder to zip archive." Why?

if i change CopyHere to :

destinationFile.CopyHere(sourceFolder, 4 | 16);

It works correctly. But it's create parent folder in archive. How to create archive with empty folders without parent folder?

1

There are 1 best solutions below

1
Node defender On

sourceFolder.Items() includes all files and subfolders in the folder.

The entire folder copied by sourceFolder, including the parent folder.

You can zip files with the following code, parent folders can be omitted and empty folders are not omitted:

    internal void CompressZip(string folderPath)
    {
        if (!Directory.Exists(folderPath))
        {
            MessageBox.Show("Directory not exist: " + folderPath);
            return;
        }

        string zipFilePath = folderPath + ".zip";

        using (FileStream zipToCreate = new FileStream(zipFilePath, FileMode.Create))
        {
            using (ZipArchive archive = new ZipArchive(zipToCreate, ZipArchiveMode.Create))
            {
                CompressFolder(folderPath, archive, "");
            }
        }
    }

    private void CompressFolder(string folderPath, ZipArchive archive, string parentFolder)
    {
        foreach (var file in Directory.GetFiles(folderPath))
        {
            string entryName = Path.Combine(parentFolder, Path.GetFileName(file));
            archive.CreateEntryFromFile(file, entryName);
        }

        foreach (var subFolder in Directory.GetDirectories(folderPath))
        {
            string entryName = Path.Combine(parentFolder, Path.GetFileName(subFolder));
            var folderEntry = archive.CreateEntry(entryName + "/");
            // Recursively add files and subfolders in the current subfolder
            CompressFolder(subFolder, archive, entryName);
        }
    }

At this time, there are empty folders and aaa.txt under my Test folder, and Test.zip is generated through the above code

enter image description here

Second update:

I'm very sorry that I don't have .net 4.0 in my computer, so some deviations occurred during the test. I found ShareZipLip 0.86.0 in the process of looking for other methods. It doesn't seem to require the .net version. You can try the following code:

internal void CompressZip(string folderPath)
{
     if (!Directory. Exists(folderPath))
     {
         MessageBox. Show("Directory not exist: " + folderPath);
         return;
     }

     string zipFilePath = folderPath + ".zip";

     using (FileStream fsOut = File. Create(zipFilePath))
     {
         using (ZipOutputStream zipStream = new ZipOutputStream(fsOut))
         {
             zipStream.SetLevel(9); // Compression level, 0-9, 9 means the highest compression

             CompressFolder(folderPath, zipStream, "");
         }
     }
}

private void CompressFolder(string folderPath, ZipOutputStream zipStream, string parentFolder)
{
     string[] files = Directory. GetFiles(folderPath);
     foreach (string file in files)
     {
         string entryName = Path. Combine(parentFolder, Path. GetFileName(file));
         ZipEntry newEntry = new ZipEntry(entryName);
         zipStream.PutNextEntry(newEntry);

         using (FileStream fs = File. OpenRead(file))
         {
             byte[] buffer = new byte[4096];
             StreamUtils. Copy(fs, zipStream, buffer);
         }

         zipStream. CloseEntry();
     }

     string[] subFolders = Directory. GetDirectories(folderPath);
     foreach (string subFolder in subFolders)
     {
         string entryName = Path. Combine(parentFolder, Path. GetFileName(subFolder));
         ZipEntry newEntry = new ZipEntry(entryName + "/");
         zipStream.PutNextEntry(newEntry);
         CompressFolder(subFolder, zipStream, entryName);
     }
}