在nodejs中重命名zip存档内的文件

Rename files inside zip archive in nodejs

我正在编写一个应该执行以下操作的 nodejs 脚本:

  1. 下载 zip 文件
  2. 删除 zip 文件的顶级目录(将所有文件向上移动一个文件夹)
  3. 上传新的 zip 文件

由于zip文件较大,我想重命名(或移动)文件而不解压并重新压缩文件。

这可能吗?

是的,有可能 使用像 adm-zip

这样的库
var AdmZip = require('adm-zip');

//create a zip object to hold the new zip files
var newZip = new AdmZip();

// reading archives
var zip = new AdmZip('somePath/download.zip');
var zipEntries = zip.getEntries(); // an array of ZipEntry records

zipEntries.forEach(function(zipEntry) {
    var fileName = zipEntry.entryName;
    var fileContent = zip.readAsText(fileName)
    //Here remove the top level directory
    var newFileName = fileName.substring(fileName.indexOf("/") + 1);

    newZip.addFile(newFileName, fileContent, '', 0644 << 16);        
});

newZip.writeZip('somePath/upload.zip');  //write the new zip 

算法

创建一个 newZip 对象来临时将文件保存在内存中 阅读下载的 zip 中的所有条目。对于每个条目

  1. 读取文件名。这包括路径
  2. 使用文件名读取文件内容
  3. 去掉顶层目录名得到新文件名
  4. 将步骤 2 中的文件内容添加到 newZip,为其提供步骤 3 中的新文件名
  5. 最后,将 newZip 写到磁盘,给它一个新的 zipName

希望对您有所帮助

您可以使用具有异步承诺风格的优秀 jszip 库。

import jszip from 'jszip';
import fs from 'fs';

/**
 * Move/rename entire directory tree within a zip.
 * @param {*} zipFilePath The original zip file
 * @param {*} modifiedZipFilePath The path where palace the modified zip 
 * @param {*} originalDir The original directory to change
 * @param {*} destinationDir The new directory to move to.
 */
async function moveDirectory(zipFilePath, modifiedZipFilePath, originalDir, destinationDir) {

    // Read zip file bits buffer
    const zipFileBuffer = await fs.promises.readFile(zipFilePath);
    // Load jszip instance
    const zipFile = await jszip.loadAsync(zipFileBuffer);
    // Get the original directory entry
    const originalDirContent = zipFile.folder(originalDir);
    // Walk on all directory tree
    originalDirContent.forEach((path, entry) => {
        // If it's a directory entry ignore it.
        if (entry.dir) {
            return;
        }
        // Extract the file path within the directory tree 
        const internalDir = path.split(originalDir)[0];
        // Build the new file directory in the new tree 
        const newFileDir = `${destinationDir}/${internalDir}`;
        // Put the file in the new tree, with the same properties
        zipFile.file(newFileDir, entry.nodeStream(), { 
            createFolders: true,
            unixPermissions: entry.unixPermissions,
            comment: entry.comment,
            date: entry.date,
        });
    });
    // After all files copied to the new tree, remove the original directory tree.
    zipFile.remove(originalDir);
    // Generate the new zip buffer
    const modifiedZipBuffer = await zipFile.generateAsync({ type: 'nodebuffer' });
    // Save the buffer as a new zip file
    await fs.promises.writeFile(modifiedZipFilePath, modifiedZipBuffer);
}

moveDirectory('archive.zip', 'modified.zip', 'some-dir/from-dir', 'some-other-dir/to-dir');

这只是遍历所有原始目录树条目并将它们放入新目录树中。