我正在寻找一种方法来为我的解决方案添加嵌入式资源。此资源将是包含大量文件的文件夹。根据用户需求,他们需要解压缩。
我正在寻找一种在可执行文件中存储此类文件夹的方法,而不涉及第三方库(看起来相当愚蠢,但这是任务)。
我发现,我可以使用标准库GZip和UnGZip。但是GZip只处理单个文件。在这种情况下,TAR应该来到现场。但我没有在标准类中找到TAR实现。
也许有可能用裸C#解压缩TAR?
答案 0 :(得分:6)
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)
{
reader.WriteEntryToDirectory(directoryPath, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
}
}
答案 1 :(得分:6)
在寻找相同问题的快速答案时,我遇到了这个线程,并且对当前答案并不完全满意,因为它们都指向对更大的库使用第三方依赖,所有这些都只是为了实现简单将tar.gz
文件提取到磁盘。
虽然gz
格式被认为相当复杂,但是tar
却很简单。从本质上讲,它只需要处理一堆文件,为每个描述文件的文件添加一个500字节的标头(但需要512字节),并将它们全部以512字节的对齐方式写入单个存档。没有压缩,通常通过将创建的文件压缩到gz
存档中来处理,.NET方便地内置了该存档,该存档处理了所有困难的部分。
查看了tar
格式的spec以来,实际上只有2个值(特别是在Windows上),我们需要从标题中挑选出来以便从流中提取文件。第一个是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,带有一些注释。
答案 2 :(得分:4)
请参阅tar-cs
using (FileStream unarchFile = File.OpenRead(tarfile))
{
TarReader reader = new TarReader(unarchFile);
reader.ReadToEnd("out_dir");
}
答案 3 :(得分:2)
由于您不允许使用外部库,因此您也不限于tar
文件的特定格式。实际上,他们甚至不需要将它们全部放在同一个文件中。
您可以在C#中编写自己的类似tar的实用程序,它可以遍历目录树,并生成两个文件:一个“头”文件,包含将System.IO.Path
个实例映射到偏移/长度对的序列化字典,和一个大文件,包含连接成一个巨型blob的单个文件的内容。这不是一项微不足道的任务,但也不过分复杂。
答案 4 :(得分:0)
有两种方法可以在.NET中进行压缩/解压缩,首先你可以使用Gzipstream类,DeflatStream实际上可以用.gz格式压缩你的文件,所以如果你压缩Gzipstream中的任何文件,它可以用任何流行的压缩应用程序打开比如winzip / winrar,7zip但你无法用DeflatStream打开压缩文件。这两个类来自.NET 2.
还有另一种方法是Package类它实际上与Gzipstream和DeflatStream相同,唯一不同的是你可以压缩多个文件然后可以用winzip / winrar打开,7zip.so就是所有的.NET。但它甚至不是通用的.zip文件, 它是微软用来压缩* x扩展办公文件的东西。如果使用包类解压缩任何docx文件,则可以看到存储在其中的所有内容。因此,不要使用.NET库进行压缩甚至解压缩,因为您甚至无法制作通用压缩文件,甚至无法解压缩通用zip文件。你必须考虑第三方库,如 http://www.icsharpcode.net/OpenSource/SharpZipLib/
或从底层实施所有内容。