在 JS 中重建解压的 zip 文件的 file/folder 结构
Reconstructing file/folder structure of a decompressed zip file in JS
我正在尝试用 JavaScript 在浏览器中重建解压缩的 zip 文件的 file/folder 结构。理想情况下,我希望所有文件都在 FileList
(就像他们刚刚通过网页上传一样)或其他可迭代对象。例如,包含
的压缩文件夹
folder/file1
folder/file2
someotherfile
应该重构为一个FileList/iterable对象,其中每一项对应包中的一个文件(据我所知,在JS中无法保留文件夹结构)。
我已经非常成功地读取了一个 tar.gz 文件并使用 pako 将其解压到这个问题底部的代码中。但是,pako 的结果是一个很大的 ArrayBuffer(下面代码中的 inflator.result
),在尝试重建原始文件和文件夹时,我无法从中得出正面或反面。我遇到了以下问题:
- 我如何知道 ArrayBuffer 中一个文件的结束位置和另一个文件的开始位置?
- 如何判断当前文件的原始文件类型?
一旦我知道了这一点,我应该能够将 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;
}
A .tar.gz 文件是一个 tar 文件('Tape ARchive' - 因为最初捆绑文件以存储在磁带上是它的主要目的)随后被压缩。对于基于 bzip 的压缩,您可以获得 tar.bz 等变体。
请注意,这与最初由 PKZIP 创建的 .zip 文件格式不同,后者在单个 step/specification.
中处理捆绑 (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.
}
);
这似乎是您所需要的。
(请注意,我无法保证此模块的适用性或可靠性,因为我从未使用过它,但这应该为您提供一个重要的tar提示点和继续进行的上下文)。
在 ChrisM 的回答和他对 js-untar 的参考的帮助下,我设法编写了以下内容,它完成了漂亮的工作:
import pako from 'pako';
import isFunction from 'lodash/isFunction';
import untar from 'js-untar';
class FileStreamer {
...
}
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 await untar(inflator.result.buffer);
}
解压缩函数的结果现在是一个包含 File 对象的数组。甚至检索了存档文件中有关原始路径的信息。
我正在尝试用 JavaScript 在浏览器中重建解压缩的 zip 文件的 file/folder 结构。理想情况下,我希望所有文件都在 FileList (就像他们刚刚通过网页上传一样)或其他可迭代对象。例如,包含
的压缩文件夹folder/file1
folder/file2
someotherfile
应该重构为一个FileList/iterable对象,其中每一项对应包中的一个文件(据我所知,在JS中无法保留文件夹结构)。
我已经非常成功地读取了一个 tar.gz 文件并使用 pako 将其解压到这个问题底部的代码中。但是,pako 的结果是一个很大的 ArrayBuffer(下面代码中的 inflator.result
),在尝试重建原始文件和文件夹时,我无法从中得出正面或反面。我遇到了以下问题:
- 我如何知道 ArrayBuffer 中一个文件的结束位置和另一个文件的开始位置?
- 如何判断当前文件的原始文件类型?
一旦我知道了这一点,我应该能够将 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;
}
A .tar.gz 文件是一个 tar 文件('Tape ARchive' - 因为最初捆绑文件以存储在磁带上是它的主要目的)随后被压缩。对于基于 bzip 的压缩,您可以获得 tar.bz 等变体。
请注意,这与最初由 PKZIP 创建的 .zip 文件格式不同,后者在单个 step/specification.
中处理捆绑 (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.
}
);
这似乎是您所需要的。
(请注意,我无法保证此模块的适用性或可靠性,因为我从未使用过它,但这应该为您提供一个重要的tar提示点和继续进行的上下文)。
在 ChrisM 的回答和他对 js-untar 的参考的帮助下,我设法编写了以下内容,它完成了漂亮的工作:
import pako from 'pako';
import isFunction from 'lodash/isFunction';
import untar from 'js-untar';
class FileStreamer {
...
}
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 await untar(inflator.result.buffer);
}
解压缩函数的结果现在是一个包含 File 对象的数组。甚至检索了存档文件中有关原始路径的信息。