4

我一直在寻找一种解决方案,可以使用 C# 从 .tgz 或 .tar.gz 存档中读取一个或多个文件,而无需将文件提取到磁盘。

我已经确定了许多在 GNU 许可下发布的第三方库,它们允许某人提取 .tgz 存档,但没有任何运气找到解决方案来读取文件而不先提取它。

如果可能的话,我想坚持使用标准库 - 有没有人有使用 GZipStream 或任何其他方法的解决方案?谢谢!

编辑:

我想实现类似于以下内容:

public static void Decompress2(FileInfo fileToDecompress)
{
    using (FileStream fileStream = fileToDecompress.OpenRead())
    {
        using (var memStream = new MemoryStream())
        {
            string currentFileName = fileToDecompress.FullName;
            string newFileName = currentFileName.Remove(currentFileName.Length - fileToDecompress.Extension.Length);

            using (FileStream decompressedFileStream = File.Create(newFileName))
            {
                using (GZipStream decompressionStream = new GZipStream(fileStream, CompressionMode.Decompress))
                {
                    byte[] bytes = new byte[4096];
                    int n;
                    while ((n = decompressionStream.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        memStream.Write(bytes, 0, n);
                    }
                }
            }
        }
    }
}

文件是从 .tgz 或 .tar.gz 存档中提取并加载到内存中。提取到内存后,我需要能够读取提取文件的内容。提供的代码应该允许我提取 .gz 但我不确定如何添加对 .tar 的支持或如何在文件加载到内存后读取文件。

4

1 回答 1

4

刚刚使用新 BSD 许可的 tar-cs 库实现了(博客文章)tar.gz-archive 提取示例。该示例演示了如何将 tar.gz-archive 的内容提取到磁盘。

/// <summary>
/// Example of tar-cs library usage to extract tar.gz-archives.
/// Please use the latest version (from trunk) of the library.
/// </summary>
public static class TarGZip
{
    public static void Extract(string inputFile, string outputDirectory)
    {
        using (FileStream inputStream = File.OpenRead(inputFile))
        using (Stream tarStream = UnGZipSteam(inputStream))
        {
            var tarReader = new TarReader(tarStream);
            while (tarReader.MoveNext(false)) // Moves pointer to the next file in the tar archive.
            {
                ExtractTarEntry(tarReader, outputDirectory);
            }
        }
    }

    /// <summary>
    /// Since GZipStream.Position Property is not implemented,
    /// it is necessary to use MemoryStream as intermediate storage.
    /// </summary>
    /// <param name="inputStream">The input stream.</param>
    /// <returns>Un-gzipped stream.</returns>
    private static Stream UnGZipSteam(Stream inputStream)
    {
        using (GZipStream gZipStream = new GZipStream(inputStream, CompressionMode.Decompress))
        {
            MemoryStream memoryStream = new MemoryStream();
            gZipStream.CopyTo(memoryStream);
            memoryStream.Position = 0;
            return memoryStream;
        }
    }

    private static void ExtractTarEntry(TarReader tarReader, string outputDirectory)
    {
        string relativePath = tarReader.FileInfo.FileName;

        // Relative path can contain slash, not backslash.
        // Use Path.GetFullPath() method to convert path.
        string fullPath = Path.GetFullPath(Path.Combine(outputDirectory, relativePath));

        switch (tarReader.FileInfo.EntryType)
        {
            case EntryType.File:
            case EntryType.FileObsolete:
                using (FileStream outputStream = File.Create(fullPath))
                {
                    // Read data from a current file to a Stream.
                    tarReader.Read(outputStream);
                }
                break;
            case EntryType.Directory:
                Directory.CreateDirectory(fullPath);
                break;
            default:
                throw new NotSupportedException("Not supported entry type: " + tarReader.FileInfo.EntryType);
        }
    }
}

请注意,由于未实现GZipStream.Position 属性,因此需要使用 MemoryStream 作为中间存储或实现具有属性支持的GZipStream包装器。Position

于 2013-10-06T12:55:30.507 回答