How to create tar.gz file in C#
Asked Answered
F

3

13


I have tried SevenZipLib and SevenZipSharp, but without success. Can someone give me a working example of archiving a text file to tar.gz, using any free library?
I know it's not the best way to go for zipping, but it's a requirement I have.

Friedrick answered 5/8, 2015 at 15:19 Comment(1)
Both of the libraries you linked support tar and gz, although they are rather old. Did you encounter a specific problem?Adjoint
A
16

Perhaps the most popular package in NuGet that supports TAR is SharpZipLib. Its wiki includes examples for working with tar.gz files, including creation. The linked example archives an entire folder.

To archive a single file, the sample can be simplified to this:

private void CreateTarGZ(string tgzFilename, string fileName)
{
    using (var outStream = File.Create(tgzFilename))
    using (var gzoStream = new GZipOutputStream(outStream))
    using (var tarArchive = TarArchive.CreateOutputTarArchive(gzoStream))
    {
        tarArchive.RootPath = Path.GetDirectoryName(fileName);

        var tarEntry = TarEntry.CreateEntryFromFile(fileName);
        tarEntry.Name = Path.GetFileName(fileName);

        tarArchive.WriteEntry(tarEntry,true);
    }
}

Essentially, you need to create a TarEntry for each folder and file you want to store.

Adjoint answered 5/8, 2015 at 15:44 Comment(1)
I have managed to change the requirement and work with zip files, but I believe your answer would work...Friedrick
F
4

Not a fan of the examples on how to compress a directory provided by SharpZipLib because instead of keeping the folder structure in the directory you are trying to convert to a .tgz, their method copies the folder path that leads to whatever directory you are trying to compress.

For example:

If you were trying to compress folderA (located in: //filer/folder1/folderA) with a single file called foo.c, then after converting folderA into a .tgz, the path to foo.c within the .tgz file would be:

folderA.tgz/filer/folder1/foo.c

This solution omits the extra files within the .tgz, resulting in:

folderA.tgz/foo.c

using ICSharpCode.SharpZipLib.GZip;
using ICSharpCode.SharpZipLib.Tar;
using ICSharpCode.SharpZipLib.Zip;
using System.IO;

/// <summary>
/// Creates a .tgz file using everything in the sourceDirectory. The .tgz file will be titled {tgzFileName}.tgz and will be located in targetDirectory.
/// </summary>
/// <param name="sourceDirectory">Directory to compress into a .tgz</param>
/// <param name="tgzFileName">Name of .tgz file</param>
/// <param name="targetDirectory">Directory where {tgzFileName}.tgz should be located.</param>
/// <param name="deleteSourceDirectoryUponCompletion">Will delete sourceDirectory if <see langword="true"/></param>
/// <returns>Path to .tgz file</returns>
public string CreateTGZ(string sourceDirectory, string tgzFileName, string targetDirectory, bool deleteSourceDirectoryUponCompletion = false)
{
    if (!tgzFileName.EndsWith(".tgz"))
    {
        tgzFileName = tgzFileName + ".tgz";
    }
    using (var outStream = File.Create(Path.Combine(targetDirectory, tgzFileName)))
    using (var gzoStream = new GZipOutputStream(outStream))
    {
        var tarArchive = TarArchive.CreateOutputTarArchive(gzoStream);

        // Note that the RootPath is currently case sensitive and must be forward slashes e.g. "c:/temp"
        // and must not end with a slash, otherwise cuts off first char of filename
        tarArchive.RootPath = sourceDirectory.Replace('\\', '/');
        if (tarArchive.RootPath.EndsWith("/"))
        {
            tarArchive.RootPath = tarArchive.RootPath.Remove(tarArchive.RootPath.Length - 1);
        }

        AddDirectoryFilesToTGZ(tarArchive, sourceDirectory);

        if (deleteSourceDirectoryUponCompletion)
        {
            File.Delete(sourceDirectory);
        }

        var tgzPath = (tarArchive.RootPath + ".tgz").Replace('/', '\\');

        tarArchive.Close();
        return tgzPath;
    }
}

private void AddDirectoryFilesToTGZ(TarArchive tarArchive, string sourceDirectory)
{
    AddDirectoryFilesToTGZ(tarArchive, sourceDirectory, string.Empty);
}

private void AddDirectoryFilesToTGZ(TarArchive tarArchive, string sourceDirectory, string currentDirectory)
{
    var pathToCurrentDirectory = Path.Combine(sourceDirectory, currentDirectory);

    // Write each file to the tgz.
    var filePaths = Directory.GetFiles(pathToCurrentDirectory);
    foreach (string filePath in filePaths)
    {
        var tarEntry = TarEntry.CreateEntryFromFile(filePath);

        // Name sets where the file is written. Write it in the same spot it exists in the source directory
        tarEntry.Name = filePath.Replace(sourceDirectory, "");

        // If the Name starts with '\' then an extra folder (with a blank name) will be created, we don't want that.
        if (tarEntry.Name.StartsWith('\\'))
        {
            tarEntry.Name = tarEntry.Name.Substring(1);
        }
        tarArchive.WriteEntry(tarEntry, true);
    }

    // Write directories to tgz
    var directories = Directory.GetDirectories(pathToCurrentDirectory);
    foreach (string directory in directories)
    {
        AddDirectoryFilesToTGZ(tarArchive, sourceDirectory, directory);
    }
}
Fessler answered 25/10, 2018 at 18:47 Comment(1)
there is small error in code, returned value is not 'Path to .tgz file' but path to source directory with .tgz extension. .tgz file created in folder specified by 'targetDirectory' argument. var tgzPath = (tarArchive.RootPath + ".tgz").Replace('/', '\\'); fix would be, for example, replacing return tgzPath; by return targetDirectory + Path.GetFileName( tgzPath );Opportunity
F
-2

The following solution might work as well: How to Create a Tar GZipped File in C#

I haven't tested it, as I am not going to work with tar.gz files after all, but looks thorough and people said it works.

Friedrick answered 6/8, 2015 at 8:5 Comment(1)
The example in this link uses the same package that the answer from Panagiotis Kanavos uses.Fessler

© 2022 - 2024 — McMap. All rights reserved.