Creating Directories in a Ziparchive C# .Net 4.5

Creating Directories in a ZipArchive C# .Net 4.5

You can use something like the following, in other words, create the directory structure by hand:

using (var fs = new FileStream("1.zip", FileMode.Create))
using (var zip = new ZipArchive(fs, ZipArchiveMode.Create))
{
zip.CreateEntry("12/3/"); // just end with "/"
}

Adding a directory to an existing .zip file

I managed to find a way to do this thanks to @stuartd. He pointed me to this answer https://stackoverflow.com/a/22339337/3182972 and I found a way to implement it into my code that creates directories with files inside them from a source location of said directories.

Here is the code:

   using (FileStream zipToOpen = new FileStream("c:\MyDestination\test.zip", FileMode.Open))
{
using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update))
{
ZipArchiveEntry readmeEntry;
DirectoryInfo d = new DirectoryInfo(c:\MySourceFolder);
FileInfo[] Files = d.GetFiles("*");
foreach (FileInfo file in Files)
{
readmeEntry = archive.CreateEntryFromFile("c:\MySourceFolder"+ "\\" + file.Name, "MySourceFolder" + "/" + file.Name);
}
}
}

So what I did was go to my source directory and went through all of the files that are there and with a foreach cycle I added them to the destination folder in the zip file.

You can also get the source directory name with this code:

string sourcepath = "C:\MySourceFolder";
int ind = sourcepath.LastIndexOf("\\") + 1;
string folderName = sourcepath.Substring(ind, folder.Length - ind);

Directory.CreateDirectory() does not create folder within ZipFile

Edited:

If you are looking for more control, you can just create a function that adds files to a zip archive. You can then use recursion to add any subfolders and files.

First you can define a function that accepts a zip archive to add files to:

public void AddFolderToZip(ZipArchive archive, string rootPath, string path, bool recursive) 
{
foreach (var filePath in Directory.GetFiles(path))
{
//Remove root path portion from file path, so entry is relative to root
string entryName = filePath.Replace(rootPath, "");
entryName = entryName.StartsWith("\\") ? entryName.Substring(1) : entryName;

var entry = archive.CreateEntryFromFile(filePath, entryName);
}

if (recursive)
{
foreach (var subPath in Directory.GetDirectories(path))
{
AddFolderToZip(archive, rootPath, subPath, recursive);
}
}
}

Then you can call it using the following code:

string strStartPath = @"C:\Test\zip";
string strZipPath = @"C:\Test\output.zip";
ZipArchive archive = ZipFile.Open(strZipPath, ZipArchiveMode.Create);
bool recursive = true;

foreach (var directoryPath in Directory.GetDirectories(strStartPath))
{
AddFolderToZip(archive, strStartPath, directoryPath, recursive);
}

archive.Dispose();

This code adds each directory it finds in a top level directory. And for each directory it finds, it will use recursion to add any subdirectories or files found within those.

Can I maintain directory structure when zipping file?

@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);
}
}
}
}

Zipping files in .NET 4.5

Try this:

using (FileStream fs = new FileStream(@"C:\Temp\myZip.zip",FileMode.Create))
using (ZipArchive za = new ZipArchive(fs, ZipArchiveMode.Create))
{
za.CreateEntryFromFile(@"C:\Temp\myFile.txt", "myFile.txt");
}


Related Topics



Leave a reply



Submit