在 Nim 中从 tar.gz 档案中读取文件

reading files from tar.gz archive in Nim

正在寻找一种使用 Nim 编程语言(版本 0.11.2)从 tar.gz 存档中读取文件的方法。假设我有一个存档

/my/path/to/archive.tar.gz

以及该存档中的一个文件

my/path/to/archive/file.txt

我的目标是能够在 Nim 中逐行读取文件的内容。在 Python 中,我可以使用 tarfile 模块执行此操作。 Nim 中有 libzip 和 zlib 模块,但文档很少,也没有示例。还有 zipfiles 模块,但我不确定它是否能够处理 tar.gz 档案。

据我所知,libzip 和 zlib 不能用于读取 tar 文件(afaik 它们仅支持 zip 存档 and/or 原始字符串压缩,而 tar.gz 需要 gzip + tar).不幸的是,似乎还没有读取 tar.gz 个档案的 Nim 库。

如果您接受基于 tar 的快速简单的解决方案,您可以这样做:

import osproc

proc extractFromTarGz(archive: string, filename: string): string =
  # -z extracts
  # -f specifies filename
  # -z runs through gzip
  # -O prints to STDOUT
  result = execProcess("tar -zxf " & archive & " " & filename & " -O")

let content = extractFromTarGz("test.tar.gz", "some/subpath.txt")

如果您想要一个干净灵活的解决方案,这将是为 libarchive 库编写包装器的好机会 ;)。

在我公司的一个项目中,我们一直在使用以下模块,将 gzip 文件公开为流:

import
  zlib, streams

type
  GZipStream* = object of StreamObj
    f: GzFile

  GzipStreamRef* = ref GZipStream

proc fsClose(s: Stream) =
  discard gzclose(GZipStreamRef(s).f)

proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int =
  return gzread(GZipStreamRef(s).f, buffer, bufLen)

proc fsAtEnd(s: Stream): bool =
  return gzeof(GZipStreamRef(s).f) != 0

proc newGZipStream*(f: GzFile): GZipStreamRef =
  new result
  result.f = f
  result.closeImpl = fsClose
  result.readDataImpl = fsReadData
  result.atEndImpl = fsAtEnd
  # other methods are nil!

proc newGZipStream*(filename: cstring): GZipStreamRef =
  var gz = gzopen(filename, "r")
  if gz != nil: return newGZipStream(gz)

但您还需要能够读取 tar header 以便在未压缩的 gzip 流中找到所需文件的正确位置。您可以包装一些现有的 C 库,例如 libtar to do this, or you could roll your own implementation.

我创建了一个基本的 untar 包,可能对此有帮助:https://github.com/dom96/untar