Search code examples
c#filestreamtar

C#: How do I make a .tar file given a collection of System.IO.Stream objects?


I need to create a .tar file, but I don't have access to the filesystem as I'm working with Azure blob storage. I can get a collection of Streams for various files, but now I need a way to tar them up. I'm currently looking at SharpZipLib.

All of the examples I've seen so far work off of a directory, or at least files where a path is given, for example: ICSharpCode.SharpZipLib.Tar.TarEntry.CreateEntryFromFile()

I think I need to use something similar to the above call: TarEntry.CreateEntry(), but the intellisense on that one says:

Construct an entry with only a name. This allows the programmer to construct the entry's header 'by hand'."

If I'm headed in the right direction, the next question I need answered is: "How do I create a tar header in SharpZipLib?"

If not, then the title's question is most appropriate: "How do I make a .tar file given a collection of System.IO.Stream objects?"


Solution

  • A link was posted that just about answers the question perfectly (https://github.com/icsharpcode/SharpZipLib/issues/208). I made some minor modifications and ended up with the below method. The key in the dictionary input is the file name with the extension.

    I probably could have written using var tar = new TarOutputStream(output) to avoid having to call .Close() and risk missing it due to an exception, but I have had some issues in the past with stacking using vars in the context of IO, and I don't feel like prodding this anymore.

    private static byte[] CreateTarFromStreams(Dictionary<string, MemoryStream> files)
    {
        using (var output = new MemoryStream())
        {
            var tar = new TarOutputStream(output); // This obsolete method works. Can't be bothered to investigate further.
    
            var tarArchive = TarArchive.CreateOutputTarArchive(tar);
    
            foreach (var file in files)
            {
                var tarEntry = TarEntry.CreateTarEntry(file.Key);
    
                var bytes = file.Value.ToArray();
                var size = bytes.Length;
                tarEntry.Size = size;
    
                tar.PutNextEntry(tarEntry);
                tar.Write(file.Value.ToArray(), 0, size);
                tar.CloseEntry();
            }
    
            tar.IsStreamOwner = false;
            tar.Close();
    
            return output.ToArray();
        }
    }