网站搜索

typescript - Angular 11 - 使用 JSZip 添加文件压缩


我正在尝试将几个 txt 文件添加到一个 zip 文件中并在本地下载它。

为此,我正在使用这些库:JSZip 和 FileSaver。

这是下载按钮的“typescript”代码:

let zip = new JSZip();
zip.file("readme.txt", "Files required");
let txtFile = zip.folder("txt");
this.selectedItems?.forEach((item.name) => {
this.downloadService
.downloadFile(item.name)
.subscribe((response) => {
  let base64 = response.output.split(",");
  txtFile.file(item.name, base64[1], {base64: true});
});
});
zip.generateAsync({type:"blob"})
.then((content) => {
// see FileSaver.js
FileSaver.saveAs(content, this.fileZipName);
});

这段代码成功下载了 zip 文件,其中包含一个 readme.txt 文件和一个空的 txt 文件夹。txt 文件夹应该包含从 “downloadService” 服务获取的 txt 文件。

当然,移除返回文件的服务调用,并放入一个硬编码的 base64 文件,如果我们正确生成包含其 txt 文件夹及其中对应文件的 zip,那么所有 TXT 文件的内容都是相同的,因为是硬编码的。

let zip = new JSZip();
zip.file("readme.txt", "Files required");
let txtFile = zip.folder("txt");
this.selectedItems?.forEach((item) => {
txtFile.file(item.name, "VGVzdCBBbGltXzEw", {base64: true});
});
zip.generateAsync({type:"blob"})
.then((content) => {
// see FileSaver.js
FileSaver.saveAs(content, this.fileZipName);
});

我更新了问题,并附上我目前正在测试的代码,这会根据处理的文件生成多个压缩包,在最后一个压缩包中,它会将文件添加到txt文件夹中。但是我需要生成一个单独的压缩包。FileSaver.saveAs 位于循环中,用于获取文件,这会为每个文件生成一个压缩包,而在最后一个压缩包中,它会添加我需要的所有文件。

let zip = new JSZip();
zip.file("readme.txt", "Files required");
let txtFile = zip.folder("txt");
this.selectedItems?.forEach((item) => {
this.downloadService.downloadFile(item.name)
  .subscribe((response) => {
    let base64 = response.output.split(",");
    txtFile.file(item.name, base64[1], {base64: true});
    zip.generateAsync({type:"blob"})
      .then((content) => {
      // see FileSaver.js
      FileSaver.saveAs(content, this.fileZipName);
    });
  });
});

selectedItems:它是一个包含文件的对象数组,其中name属性包含文件的名称。

我不知道如何调用“downloadFile”服务,以便对每个存在的文件进行相应的调用,获取 base64 并将其添加到压缩文件中。

根据我们选择的文件,例如如果我们有两个文件,服务的响应将如下所示:

调用一个文件:

{"errorMessages":[],"output": "data:text/plain;base64,VGVzdCBJbmZyYTEw"}

调用一个文件:

{"errorMessages":[],"output": "data:text/plain;base64,VGVzdCBJbmZyYTEy"}

base64[1] 变量包含 txt 文件的 base64 代码。

总之,当我硬编码 base64 代码时,它工作正常,并且可以压缩内容相同的文件,但如果我尝试通过调用我的“downloadFile”服务动态获取 base64 代码,它不会将它们添加到 txt 文件夹中的 zip,也不会出现任何错误。

谢谢,

答案#1

问题是你的下载服务正在异步地在 Observable 中执行某些操作。你需要移动你的 .subscribe 块。类似这样

this.downloadService
  .downloadFile(item.name)
  .subscribe((response) => {
    let base64 = response.output.split(",");
    txtFile.file(item.name, base64[1], {base64: true});
    zip.generateAsync({type:"blob"})
      .then((content) => {
      // see FileSaver.js
      FileSaver.saveAs(content, this.fileZipName);
    });
  });
});

答案#2

我还没有能够使用 forkjoin,但这种条件按我需要的方式工作:

let zip = new JSZip();
zip.file("readme.txt", "Files required");
let txtFile = zip.folder("txt");
let i = 0;
this.selectedItems?.forEach((item) => {
this.downloadService.downloadFile(item.name)
  .subscribe((response) => {
    let base64 = response.output.split(",");
    txtFile.file(item.name, base64[1], {base64: true});
    i++;
    if (i === this.selectedItems.length) { // I have added this condition
      zip.generateAsync({type:"blob"})
      .then((content) => {
        // see FileSaver.js
        FileSaver.saveAs(content, this.fileZipName);
      });
    }
  });

});