使用 tar 存档读写整个目录(标准库)

Read and write whole directories with tar archive (Standard Library)

这是 的延续。

在我看来,std/archive/tar.ts 模块的当前实现只允许读取和写入每个文件,而不是整个目录。

到目前为止,我的参考来源是test files,它只展示了单文件处理的案例。但是,例如,如果给出了一个包含多个文件的目录 ./my-dir/ 和一个 tar 存档 ./test.tar 怎么办。

然后我如何利用 append, extract & Co. 有效地将 ./my-dir/ 写入 ./test.tar 存档并从中读取所有文件内容?

您可以使用 std/fs/walk

归档目录
import { walk, walkSync } from "https://deno.land/std/fs/walk.ts";
import { Tar } from "https://deno.land/std/archive/tar.ts";

// Async
const tar = new Tar();

for await (const entry of walk("./dir-to-archive")) {
    if (!entry.isFile) {
        continue;
    }
    await tar.append(entry.path, {
        filePath: entry.path,
    });
}

const writer = await Deno.open("./out.tar", { write: true, create: true });
await Deno.copy(tar.getReader(), writer);

Untar folders/multiple 文件的实现被破坏,它已被 this PR 修复,目前在 master 中使用 https://deno.land/std/archive/tar.ts

import { Untar } from "https://deno.land/std/archive/tar.ts";
import { ensureFile } from "https://deno.land/std/fs/ensure_file.ts";
import { ensureDir } from "https://deno.land/std/fs/ensure_dir.ts";

const reader = await Deno.open("./out.tar", { read: true });
const untar = new Untar(reader);

for await (const entry of untar) {
  console.log(entry); // metadata
  /*
    fileName: "archive/deno.txt",
    fileMode: 33204,
    mtime: 1591657305,
    uid: 0,
    gid: 0,
    size: 24400,
    type: 'file'
  */

  if (entry.type === "directory") {
    await ensureDir(entry.fileName);
    continue;
  }

  await ensureFile(entry.fileName);
  const file = await Deno.open(entry.fileName, { write: true });
  // <entry> is a reader
  await Deno.copy(entry, file);
}
reader.close();

更新

创建了一个 lib 以允许转换,包括 gzip/gunzip 创建和读取 .tar.gz

gzip

import * as Transform from "https://deno.land/x/transform/mod.ts";
const { GzEncoder } = Transform.Transformers;

/** ... **/
const writer = await Deno.open("./out.tar.gz", { write: true, create: true });
await Transform.pipeline(tar.getReader(), new GzEncoder())
    .to(writer);

writer.close();

gunzip

import * as Transform from "https://deno.land/x/transform/mod.ts";
const { GzDecoder } = Transform.Transformers;

/** ... **/
const reader = await Deno.open("./out.tar.gz", { read: true });
const untar = new Untar(
    Transform.newReader(input, new GzDecoder())
);

for await (const entry of untar) {
    console.log(entry);
}