zstd -rフォルダ-o出力.zstのために単一のファイルから複数のファイルを分離する方法は?

zstd -rフォルダ-o出力.zstのために単一のファイルから複数のファイルを分離する方法は?

マニュアルを十分読んでいないので、次のコマンドを実行しました。

$ zstd -r folder -o output.zst

次のコマンドは、出力と呼ばれるファイルを提供します。

$ unzstd output.zst 

出力ファイルには、リンクされたフォルダ内のファイルの内容全体が含まれます。

単一のファイルを複数の生ファイルに分割できるツールやプログラムはありますか?

これは私がバックアップする必要がある唯一のバックアップファイルです。

編集:私が実際に実行する必要があるもの(このスレッド) はい

# for tar version 1.31 and above
$ tar --zstd -cf output.tar.zst folder

# for tar version < 1.31
$ tar --use-compress-program zstd -cf output.tar.zst folder

答え1

この質問も投稿しました。zstd githubの問題私が学んだことは次のとおりです。ターコイズ 4973

すべての圧縮フレームは同じファイルoutput.zstにすぐに保存されます。

少なくとも理論的には、各フレームを分離して各ファイルの境界を見つける方法がありますが、もう1つの問題は、フレームのどれもファイル名やディレクトリツリーの場所を含まないということです。したがって、名前のないファイルがたくさん残ります。

正しいアーカイブ方法は、zstdをファイルメタデータの保存を担当するtarと組み合わせることです。

現在、フレームを分離できるツールやプログラムはありません。しかし、誰かがそれを使うことができますlz4frame.h

デフォルトでは、CLI はすべてのフレームを同じ解凍ファイルに連続して解凍します。

...直接プログラミングして、... ZSTD_decompressStream()APIを使用してください。

答え2

このGithubの問題コメントでは、コードを使用してファイルを再現することを提案します(ファイル名とフォルダ階層なし)。

#undef NDEBUG
#define ZSTD_STATIC_LINKING_ONLY

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <zstd.h>

static uint64_t get_file_size(char const* filename) {
  FILE* f = fopen(filename, "rb");
  assert(f != NULL);
  int ret = fseek(f, 0L, SEEK_END);
  assert(ret == 0);
  long int const size = ftell(f);
  assert(size >= 0);
  fclose(f);
  return (uint64_t)size;
}

static void read_file(char const* filename, void* buffer, size_t size) {
  FILE* f = fopen(filename, "rb");
  assert(f != NULL);
  size_t const read = fread(buffer, 1, size, f);
  assert(read == size);
  char tmp;
  assert(fread(&tmp, 1, 1, f) == 0);
  fclose(f);
}

static size_t decompress_one_frame(char const* inputPtr, char const* inputEnd, char const* outputPrefix, int idx) {
  size_t const inputSize = (size_t)(inputEnd - inputPtr);
  size_t const compressedSize = ZSTD_findFrameCompressedSize(inputPtr, inputSize);
  assert(!ZSTD_isError(compressedSize));

  size_t const decompressBound = ZSTD_decompressBound(inputPtr, compressedSize);
  assert(decompressBound != ZSTD_CONTENTSIZE_ERROR);
  void* const decompressed = malloc(decompressBound);
  assert(decompressed != NULL);

  size_t const decompressedSize = ZSTD_decompress(decompressed, decompressBound, inputPtr, compressedSize);
  assert(!ZSTD_isError(decompressedSize));


  size_t const outputFileSize = strlen(outputPrefix) + 11;
  char* const outputFile = malloc(outputFileSize);
  assert(outputFile != NULL);
  {
    size_t const written = snprintf(outputFile, outputFileSize, "%s%d", outputPrefix, idx);
    assert(written < outputFileSize);
  }
  {
    FILE* f = fopen(outputFile, "wb");
    size_t const written = fwrite(decompressed, 1, decompressedSize, f);
    assert(written == decompressedSize);
    fclose(f);
  }

  free(outputFile);
  free(decompressed);
  return compressedSize;
}

int main(int argc, char** argv) {
  if (argc != 3) {
    fprintf(stderr, "USAGE: %s FILE.zst OUT-PREFIX\n", argv[0]);
    fprintf(stderr, "Decompresses a zstd file containing more than one frame to ${OUT-PREFIX}0, ${OUT-PREFIX}1, ...\n");
    return 1;
  }
  char const* const inputFile = argv[1];
  char const* const outputPrefix = argv[2];

  size_t const inputSize = get_file_size(inputFile);
  char* const input = malloc(inputSize);
  assert(input != NULL);
  read_file(inputFile, input, inputSize);

  char const* inputPtr = input;
  char const* const inputEnd = input + inputSize;
  int idx = 0;
  while (inputPtr < inputEnd) {
    size_t const compressedSize = decompress_one_frame(inputPtr, inputEnd, outputPrefix, idx);
    inputPtr += compressedSize;
    ++idx;
  }
  assert(inputPtr == inputEnd);
  free(input);
  return 0;
}

このアプリはあなたに役立ちます。というファイルに書き込んでunzstd.clibzstdがインストールされている場合は、次のようにcc unzstd.c -lzstd -o unzstdコンパイルできます。その後、解凍するファイルがある場合は、次のようにinput.zst実行できます。

mkdir output
./unzstd input.zst output/
ls output/

圧縮した各入力ファイルに対して、圧縮順に出力/0、出力/1などの名前を付けた出力ファイルを生成します。したがって、ファイル名とディレクトリ構造は失われますが、ファイルの内容はすべて回復されます。

関連情報