- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在寻找一种方法来将嵌入式资源添加到我的解决方案中。该资源将是其中包含大量文件的文件夹。根据用户需求,它们需要被解压。
我正在寻找一种在不涉及第三方库的情况下将此类文件夹存储在可执行文件中的方法(看起来很愚蠢,但这就是任务)。
我发现,我可以使用标准库对它们进行 GZip 和 UnGZip。但是 GZip 只能处理单个文件。在这种情况下,TAR 应该到场。但是我还没有在标准类中找到 TAR 实现。
也许可以用纯 C# 解压 TAR?
最佳答案
在寻找同一问题的快速答案时,我遇到了这个线程,并且对当前的答案并不完全满意,因为它们都指向使用第三方依赖项到更大的库,所有这些只是为了实现简单将 tar.gz
文件提取到磁盘。
虽然 gz
格式可能被认为相当复杂,但另一方面,tar
却非常简单。在其核心,它只需要一堆文件,在每个描述文件的前面加上一个 500 字节的 header (但需要 512 字节),然后将它们全部写入 512 字节对齐的单个存档中。没有压缩,这通常是通过将创建的文件压缩到 gz
存档来处理的,.NET 方便地内置了它,它可以处理所有困难的部分。
查看了 spec对于 tar
格式,实际上只有 2 个值(尤其是在 Windows 上)我们需要从 header 中挑选出来,以便从流中提取文件。第一个是 name
,第二个是 size
。使用这两个值,我们只需要在流中寻找适当的位置并将字节复制到文件中。
我做了一个非常基本的、低级的方法来将 tar
存档提取到一个目录,并添加了一些辅助函数来从流或文件名中打开,并解压缩 gz
文件首先使用内置函数。
主要方法是这样的:
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('\0');
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);
}
}
这里有一些帮助函数,用于从文件打开,并在提取之前自动首先解压缩 tar.gz
文件/流。
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);
}
这是一个gist包含一些评论的完整文件。
关于c# - 使用 C# 解压 tar 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8863875/
我是一名优秀的程序员,十分优秀!