javascript - 在 JS 中重建解压缩的 zip 文件的文件/文件夹结构

标签 javascript compression arraybuffer filelist pako

我正在尝试使用 JavaScript 在浏览器中重建解压缩的 zip 文件的文件/文件夹结构。理想情况下,我希望所有文件都在 FileList 中。 (就像他们刚刚通过网页上传一样)或其他可迭代对象。例如,一个压缩文件夹包含

folder/file1
folder/file2
someotherfile

应该重构为一个 FileList/iterable 对象,其中每个项目对应于包中的一个文件(据我所知,没有办法在 JS 中保留文件夹结构)。

我已经非常成功地读取了一个 tar.gz 文件并使用 pako 解压了它。使用此问题底部的代码。但是,pako 的结果是一个大的 ArrayBuffer(下面代码中的 inflator.result),在尝试重建原始文件和文件夹时,我无法从中得出正面或反面。我遇到了以下问题:

  1. 我如何知道 ArrayBuffer 中一个文件的结束位置和另一个文件的开始位置?
  2. 如何判断当前文件的原始文件类型?

一旦我知道这一点,我应该能够将 ArrayBuffer 数据转换为一个文件

File(segment, {type: filetype})

网络搜索也没有提供任何有用的信息。有没有人知道如何解决这个问题?

这是我用来解压缩 zip 文件的代码。

import pako from 'pako';
import isFunction from 'lodash/isFunction'

class FileStreamer {
  constructor(file, chunkSize = 64 * 1024) {
    this.file = file;
    this.offset = 0;
    this.chunkSize = chunkSize; // bytes
    this.rewind();
  }
  rewind() {
    this.offset = 0;
  }
  isEndOfFile() {
    return this.offset >= this.getFileSize();
  }
  readBlock() {
    const fileReader = new FileReader();
    const blob = this.file.slice(this.offset, this.offset + this.chunkSize);

    return new Promise((resolve, reject) => {
      fileReader.onloadend = (event) => {
        const target = (event.target);
        if (target.error) {
          return reject(target.error);
        }

        this.offset += target.result.byteLength;

        resolve({
          data: target.result,
          progress: Math.min(this.offset / this.file.size, 1)
        });
      };

      fileReader.readAsArrayBuffer(blob);
    });
  }
  getFileSize() {
    return this.file.size;
  }
}

export async function decompress(zipfile, onProgress) {
  const fs = new FileStreamer(zipfile);
  const inflator = new pako.Inflate();
  let block;

  while (!fs.isEndOfFile()) {
    block = await fs.readBlock();
    inflator.push(block.data, fs.isEndOfFile());
    if (inflator.err) {
      throw inflator.err
    }
    if (isFunction(onProgress)) onProgress(block.progress)
  }

  return inflator.result;
}

最佳答案

.tar.gz 文件是一个 tar 文件('Tape ARchive' - 因为最初捆绑文件以存储在磁带上是它的主要目的)随后被压缩。您可以获得诸如基于 bzip 压缩的 tar.bz 等变体。

请注意,这与最初由 PKZIP 创建的 .zip 文件格式不同,后者在单个步骤/规范中处理捆绑 (tar) 和压缩 (gz)。

无论如何,考虑到这一点,您将需要另一种工具来解释 tar 数据并将其转化为对您的目的有用的东西。我搜索了“tar file reader js”并找到了 js-untar: https://github.com/InvokIT/js-untar

这似乎采用 ArrayBuffer 并将其转换为一系列 File 对象。来自项目页面的示例代码:

import untar from "js-untar";

// Load the source ArrayBuffer from a XMLHttpRequest (or any other way you may need).
var sourceBuffer = [...];

untar(sourceBuffer)
.progress(function(extractedFile) {
    ... // Do something with a single extracted file.
})
.then(function(extractedFiles) {
    ... // Do something with all extracted files.
});

// or

untar(sourceBuffer).then(
    function(extractedFiles) { // onSuccess
        ... // Do something with all extracted files.
    },
    function(err) { // onError
        ... // Handle the error.
    },
    function(extractedFile) { // onProgress
        ... // Do something with a single extracted file.
    }
);

这似乎是您所需要的。

(请注意,我无法保证此模块的适用性或可靠性,因为我从未使用过它,但这应该为您提供一个起点和继续进行的上下文)。

关于javascript - 在 JS 中重建解压缩的 zip 文件的文件/文件夹结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50600512/

相关文章:

javascript - 如何从 WebSocket 二进制数据显示图像?

javascript - Codeigniter 中 ajax 上传的奇怪 MIME 类型

javascript - 表单计算和 Javascript PDF 表单

math - 仍可排序的最佳整数编码

android - Android中的视频压缩

image - 检测JPEG压缩率?

javascript - 如何在 Javascript 中添加时间(分钟+分钟)? (没有日期)

javascript - 修改数据表 Vuetify 2.0 中的默认槽 isOpen

javascript - 将 JavaScript ArrayBuffer 转换为 8 位数字数组

Javascript - BYTES_PER_ELEMENT 在 Opera 中未定义