使用 C# 解压 tar 文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8863875/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 04:51:29  来源:igfitidea点击:

Decompress tar files using C#

c#.nettar

提问by shytikov

I'm searching a way to add embedded resource to my solution. This resources will be folders with a lot of files in them. On user demand they need to be decompressed.

我正在寻找一种将嵌入式资源添加到我的解决方案的方法。这些资源将是包含大量文件的文件夹。根据用户需求,它们需要被解压。

I'm searching for a way do store such folders in executable without involving third-party libraries (Looks rather stupid, but this is the task).

我正在寻找一种在不涉及第三方库的情况下将此类文件夹存储在可执行文件中的方法(看起来很愚蠢,但这就是任务)。

I have found, that I can GZip and UnGZip them using standard libraries. But GZip handles single file only. In such cases TAR should come to the scene. But I haven't found TAR implementation among standard classes.

我发现,我可以使用标准库对它们进行 GZip 和 UnGZip。但是 GZip 只能处理单个文件。在这种情况下,TAR 应该出现。但是我还没有在标准类中找到 TAR 实现。

Maybe it possible decompress TAR with bare C#?

也许可以用裸 C# 解压 TAR?

采纳答案by dasblinkenlight

Since you are not allowed to use outside libraries, you are not restricted to a specific format of the tarfile either. In fact, they don't even need it to be all in the same file.

由于不允许使用外部库,因此也不受特定tar文件格式的限制。事实上,他们甚至不需要将其全部放在同一个文件中。

You can write your own tar-like utility in C# that walks a directory tree, and produces two files: a "header" file that consists of a serialized dictionary mapping System.IO.Pathinstances to an offset/length pairs, and a big file containing the content of individual files concatenated into one giant blob. This is not a trivial task, but it's not overly complicated either.

您可以在 C# 中编写自己的类似 tar 的实用程序,它遍历目录树并生成两个文件:一个“头”文件,其中包含将System.IO.Path实例映射到偏移/长度对的序列化字典,以及一个包含以下内容的大文件单个文件连接成一个巨大的 blob。这不是一项微不足道的任务,但也不是太复杂。

回答by IanNorton

See tar-cs

tar-cs

using (FileStream unarchFile = File.OpenRead(tarfile))
{
    TarReader reader = new TarReader(unarchFile);
    reader.ReadToEnd("out_dir");
}

回答by user1120193

there are 2 ways to compress/decompress in .NET first you can use Gzipstream class and DeflatStream both can actually do compress your files in .gz format so if you compressed any file in Gzipstream it can be opened with any popular compression applications such as winzip/ winrar, 7zip but you can't open compressed file with DeflatStream. these two classes are from .NET 2.

在 .NET 中有 2 种压缩/解压缩方法,首先您可以使用 Gzipstream 类和 DeflatStream 实际上都可以压缩 .gz 格式的文件,因此如果您在 Gzipstream 中压缩任何文件,它可以使用任何流行的压缩应用程序打开,例如 winzip / winrar, 7zip 但你不能用 DeflatStream 打开压缩文件。这两个类来自 .NET 2。

and there is another way which is Package class it's actually same as Gzipstream and DeflatStream the only different is you can compress multiple files which then can be opened with winzip/ winrar, 7zip.so that's all .NET has. but it's not even generic .zip file, it something Microsoft uses to compress their *x extension office files. if you decompress any docx file with package class you can see everything stored in it. so don't use .NET libraries for compressing or even decompressing cause you can't even make a generic compress file or even decompress a generic zip file. you have to consider for a third party library such as http://www.icsharpcode.net/OpenSource/SharpZipLib/

还有另一种方式是 Package 类,它实际上与 Gzipstream 和 DeflatStream 相同,唯一不同的是您可以压缩多个文件,然后可以使用 winzip/winrar、7zip.so 打开 .NET。但它甚至不是通用的 .zip 文件,它是 Microsoft 用来压缩其 *x 扩展 Office 文件的东西。如果您使用包类解压缩任何 docx 文件,您可以看到其中存储的所有内容。所以不要使用 .NET 库进行压缩甚至解压缩,因为你甚至无法制作通用压缩文件,甚至无法解压通用 zip 文件。您必须考虑使用第三方库,例如 http://www.icsharpcode.net/OpenSource/SharpZipLib/

or implement everything from the ground floor.

或从底层实施一切。

回答by Steven Wolfe

Tar-cswill do the job, but it is quite slow. I would recommend using SharpCompresswhich is significantly quicker. It also supports other compression types and it has been updated recently.

Tar-cs可以完成这项工作,但速度很慢。我建议使用SharpCompress,它的速度要快得多。它还支持其他压缩类型,并且最近已更新。

using System;
using System.IO;
using SharpCompress.Common;
using SharpCompress.Reader;

private static String directoryPath = @"C:\Temp";

public static void unTAR(String tarFilePath)
{
    using (Stream stream = File.OpenRead(tarFilePath))
    {
        var reader = ReaderFactory.Open(stream);
        while (reader.MoveToNextEntry())
        {
            if (!reader.Entry.IsDirectory)
            {
                ExtractionOptions opt = new ExtractionOptions {
                    ExtractFullPath = true,
                    Overwrite = true
                };
                reader.WriteEntryToDirectory(directoryPath, opt);
            }
        }
    }
}

回答by ForeverZer0

While looking for a quick answer to the same question, I came across this thread, and was not entirely satisfied with the current answers, as they all point to using third-party dependencies to much larger libraries, all just to achieve simple extraction of a tar.gzfile to disk.

在寻找同一问题的快速答案时,我遇到了这个线程,并且对当前的答案并不完全满意,因为它们都指向对更大的库使用第三方依赖项,所有这些只是为了实现简单的提取tar.gz文件到磁盘。

While the gzformat could be considered rather complicated, taron the other hand is quite simple. At its core, it just takes a bunch of files, prepends a 500 byte header (but takes 512 bytes) to each describing the file, and writes them all to single archive on a 512 byte alignment. There is no compression, that is typically handled by compressing the created file to a gzarchive, which .NET conveniently has built-in, which takes care of all the hard part.

虽然gz格式可能被认为相当复杂,tar但另一方面却非常简单。在其核心,它只需要一堆文件,在每个描述文件的前面加上一个 500 字节的标头(但需要 512 字节),然后将它们全部写入到 512 字节对齐的单个存档中。没有压缩,通常通过将创建的文件压缩到gz存档来处理,.NET 方便地内置了存档,它负责处理所有困难的部分。

Having looked at the specfor the tarformat, there are only really 2 values (especially on Windows) we need to pick out from the header in order to extract the file from a stream. The first is the name, and the second is size. Using those two values, we need only seek to the appropriate position in the stream and copy the bytes to a file.

说完看了看规范tar格式,只有真正的2个值(特别是在Windows),我们需要以从流中提取文件从头挑出来。第一个是name,第二个是size。使用这两个值,我们只需要寻找流中的适当位置并将字节复制到文件中。

I made a very rudimentary, down-and-dirty method to extract a tararchive to a directory, and added some helper functions for opening from a stream or filename, and decompressing the gzfile first using built-in functions.

我制作了一个非常基本的、简陋的方法来将tar档案提取到目录中,并添加了一些帮助函数,用于从流或文件名打开,并gz首先使用内置函数解压缩文件。

The primary method is this:

主要方法是这样的:

public static void ExtractTar(Stream stream, string outputDir)
{
    var buffer = new byte[100];
    while (true)
    {
        stream.Read(buffer, 0, 100);
        var name = Encoding.ASCII.GetString(buffer).Trim('
public static void ExtractTarGz(string filename, string outputDir)
{
    using (var stream = File.OpenRead(filename))
        ExtractTarGz(stream, outputDir);
}

public static void ExtractTarGz(Stream stream, string outputDir)
{
    // A GZipStream is not seekable, so copy it first to a MemoryStream
    using (var gzip = new GZipStream(stream, CompressionMode.Decompress))
    {
        const int chunk = 4096;
        using (var memStr = new MemoryStream())
        {
            int read;
            var buffer = new byte[chunk];
            do
            {
                read = gzip.Read(buffer, 0, chunk);
                memStr.Write(buffer, 0, read);
            } while (read == chunk);

            memStr.Seek(0, SeekOrigin.Begin);
            ExtractTar(memStr, outputDir);
        }
    }
}

public static void ExtractTar(string filename, string outputDir)
{
    using (var stream = File.OpenRead(filename))
        ExtractTar(stream, outputDir);
}
'); if (String.IsNullOrWhiteSpace(name)) break; stream.Seek(24, SeekOrigin.Current); stream.Read(buffer, 0, 12); var size = Convert.ToInt64(Encoding.ASCII.GetString(buffer, 0, 12).Trim(), 8); stream.Seek(376L, SeekOrigin.Current); var output = Path.Combine(outputDir, name); if (!Directory.Exists(Path.GetDirectoryName(output))) Directory.CreateDirectory(Path.GetDirectoryName(output)); using (var str = File.Open(output, FileMode.OpenOrCreate, FileAccess.Write)) { var buf = new byte[size]; stream.Read(buf, 0, buf.Length); str.Write(buf, 0, buf.Length); } var pos = stream.Position; var offset = 512 - (pos % 512); if (offset == 512) offset = 0; stream.Seek(offset, SeekOrigin.Current); } }

And here is a few helper functions for opening from a file, and automating first decompressing a tar.gzfile/stream before extracting.

这里有一些帮助函数,用于从文件打开,并tar.gz在提取之前自动首先解压缩文件/流。

##代码##

Here is a gistof the full file with some comments.

这是完整文件的要点和一些评论。