在Node.js中重命名zip归档文件内的文件

6
我正在编写一个nodejs脚本,它应该执行以下操作:
  1. 下载zip文件
  2. 删除zip文件的顶层目录(将所有文件移动到上一级文件夹)
  3. 上传新的zip文件
因为zip文件比较大,我希望在不解压和重新压缩文件的情况下重命名(或移动)文件。这是否可能?
3个回答

4

没问题,可以使用像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 

算法

创建一个新的Zip对象来临时存储文件在内存中 读取下载的zip文件中的所有条目。对于每个条目,执行以下操作

  1. 读取文件名,包括路径
  2. 使用文件名读取文件内容
  3. 删除顶层目录名称以获得新文件名
  4. 将步骤2中的文件内容添加到新Zip中,并赋予它步骤3中的新文件名
  5. 最后,将新Zip写入磁盘,并给它一个新的zip名称

希望这有所帮助


2

您可以使用优秀的jszip库,以异步Promise方式进行操作。

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');


这只是在所有原始目录树条目上简单地遍历并将它们放置在新目录树中。

0
为了回答Vitalis的回答,我创建了一个编辑版本,因为有太多的待处理编辑。
const AdmZip = require('adm-zip');

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

// read existing zip
const oldZip = new AdmZip('somePath/download.zip');
const zipEntries = oldZip.getEntries(); // an array of ZipEntry records

zipEntries.forEach(function(zipEntry) {
  let oldEntryName = zipEntry.entryName;
  let fileContent = oldZip.readFile(oldEntryName) || Buffer.alloc(0);
  // remove the top level directory
  let newEntryName = oldEntryName.substring(oldEntryName.indexOf("/") + 1);

  newZip.addFile(newEntryName, fileContent);        
});

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

commentattr参数对于newZip.addFile()来说是可选的。事实上,0644 << 16应该写成0o644 << 16,当压缩文件被解压时,它还会禁止您读取该文件。

fileContent需要是一个缓冲区而不是字符串。在旧的压缩文件中,如果不幸地发生条目异常消失的情况,将提供一个回退选项(Buffer.alloc(0))。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接