【问题标题】:Node.js AWS Lambda + Archiver lib - Error in zip file creationNode.js AWS Lambda + Archiver lib - 创建压缩文件时出错
【发布时间】:2022-02-17 23:52:09
【问题描述】:

大家,

我在 Node.js 中编写了一个 lambda,它获取一个文件夹并压缩其内容。 为此,我使用了 Archiver 库:Archiver

以下是我创建文件的代码:

const zipFilePath = '/tmp/' + 'filename' + '.zip'
const output = fs.createWriteStream(zipFilePath);

const archive = archiver('zip', {
    zlib: { level: 9 }
});

output.on('close', function () {
    console.log(archive.pointer() + ' total bytes');
    console.log('archiver has been finalized and the output file descriptor has closed.');
});

archive.on('error', function(err){
    throw err;
});

await archive.pipe(output);
await archive.directory(destFolder, false);
await archive.finalize();

要写入文件,我使用 lambdas 的 /tmp 文件夹,这是唯一具有写入权限的文件夹。

流程如下:

  1. 我得到了文件夹的路径
  2. 压缩内容并将其保存在文件夹destFolder中

然后将文件保存在 S3 存储桶中:

const file = await fs.readFileSync(filePath)
const params = {
    Bucket: bucketName,
    Key: fileName,
    Body: file
};
const res = await s3.upload(params).promise()
return res.Location

生成了zip文件,问题是当我下载它时,它已损坏。我尝试使用在线 zip 文件分析器 (this) 对其进行分析,分析结果如下:

Type = zip
ERRORS:
Unexpected end of archive
WARNINGS:
There are data after the end of archive
Physical Size = 118916
Tail Size = 19
Characteristics = Local

分析器显示文件都存在于 .zip 中(我可以看到它们的名称)。

最奇怪的是,如果不是 .zip 文件(同样使用相同的库)我在 .tar 中创建它

const archive = archiver('tar', {
    zlib: { level: 9 }
});

文件已正确生成,我可以将其解压缩为存档。基本上,就好像 .zip 格式本身有问题。

有没有人经历过类似的情节?你能帮我找到解决办法吗?我需要以 .zip 格式创建文件。 谢谢。

【问题讨论】:

    标签: node.js amazon-web-services amazon-s3 aws-lambda zip


    【解决方案1】:

    问题是您无法正确压缩文件,这可能由许多问题引起,包括:

    • 您没有等待处理文件,您需要使用.close() 事件来执行此操作。
    • 您没有将正确的路径发送到要压缩的文件或目录,通常您上传的文件与项目根目录上的 lambda 文件一起保留在 Lambda 目录系统上的 /var/task/ 上,因此要发送正确的文件使用__dirname + '/file.name'
    • 您没有正确附加文件,如果您正确发送文件,请检查.file().append() 方法

    如果您有以下 Lambda 结构:

    ~/my-function
    ├── index.js
    └── node_modules
    ├── package.json
    ├── package-lock.json
    ├── test.txt //file to be sent zipped on s3
    

    以下示例适用于您:

    const archiver = require('archiver')
    const fs = require('fs')
    const AWS = require('aws-sdk');
    const s3 = new AWS.S3({apiVersion: '2006-03-01'});
    
    
    const sendToS3 = async (filePath) => {
        const bucketName = "bucket_name";
        const fileName = "zipped.zip"
        const file = await fs.readFileSync(filePath)
        const params = {
            Bucket: bucketName,
            Key: fileName,
            Body: file
        };
        const res = await s3.upload(params).promise()
        return res.Location
    }
    
    exports.handler = async event => {
      return new Promise((resolve, reject) => {
        const zippedPathName = '/tmp/example.zip';
        const output = fs.createWriteStream(zippedPathName);
        const fileToBeZipped = __dirname + '/test.txt';
        const zip = archiver('zip')
    
        zip
          .append(fs.createReadStream(fileToBeZipped), { name: 'test.txt' })
          .pipe(output)
    
        zip.finalize()
    
        output.on('close', (result => {
            sendToS3(zippedPathName).then(result => {
                resolve(result)
            })
        }))
      })
    }
    

    【讨论】:

    • 嗨@valdeci,您的解决方案完美运行!我稍微修改了代码,因为我需要压缩包含文件而不是单个文件的目录,所以我使用了 .directory() 方法而不是 .append()。但是,我保留了 Lambdas 的 /tmp 文件夹,因为从我在文档中阅读的内容来看,它是唯一可写的文件夹。你知道 /var/task 是否也是可写的吗?你知道/tmp文件夹执行后是否会自动清空吗?再次感谢!
    • /var/task 是保存函数文件的目录,该目录是不可写的(例如,如果您上传一个 test.txt 并带有您为您的函数上传的代码将能够读取它),/tmp 只是您在 Lambda 函数中拥有的可写目录
    • 谢谢!这正是我想要的。
    猜你喜欢
    • 2017-03-07
    • 1970-01-01
    • 2016-05-16
    • 2018-11-27
    • 1970-01-01
    • 2018-11-27
    • 2020-09-30
    • 2013-03-09
    • 1970-01-01
    相关资源
    最近更新 更多