0

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?"

eriyg
  • 99
  • 1
  • 12
  • 1
    There is nothing in .NET named `System.IO.Streams` - but there is the `class System.IO.Stream` type - but I don't see how that's _specifically_ relevant to this problem because practically _all_ sequential IO in .NET goes through _some_ kind of `Stream` subclass somewhere (e.g. `FileStream`, `NetworkStream`, etc). – Dai May 08 '23 at 17:45
  • 1
    might help: https://github.com/icsharpcode/SharpZipLib/issues/208 – Christoph Lütjen May 08 '23 at 18:05
  • @Dai Yes, other teams mandate that I use .tar They have a habit of creating poor architecture and I can't do anything to fix it (I've tried). For your other comment, I meant the english plural form of System.IO.Stream, thus System.IO.Streams – eriyg May 08 '23 at 19:24
  • @ChristophLütjen This is exactly what I needed. I only had to make a few minor modifications and it worked. If you write this up as the answer, I'll mark it as correct. Otherwise I'll write it up myself in a few days. – eriyg May 08 '23 at 20:00

1 Answers1

0

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();
    }
}
eriyg
  • 99
  • 1
  • 12