You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将ZIP压缩文件特性从UTF8修改为Descriptor UTF8?

提问

我用yazl库写了一个POC,用来生成包含XML文件的ZIP压缩包。目前压缩包的特性显示为“UTF8”,但我需要将其改为“Descriptor UTF8”。试过多个压缩库都没解决这个问题,求有经验的人帮忙。

格式对比

  • 预期特性:Descriptor UTF8
  • 当前特性:UTF8

POC代码

const yazl = require('yazl');
const fs = require('fs');
const path = require('path');
 
function test(
    location,
    ackId,
    responseContent,
    responsezipFileName,
    responsefileName
) {
    return new Promise((resolve, reject) => {
        const zipFile = new yazl.ZipFile();
 
        // 确保内容是UTF-8编码的Buffer
        const contentBuffer = Buffer.isBuffer(responseContent) ? responseContent : Buffer.from(responseContent, 'utf8');
 
        // 将日期转换为DOS日期/时间格式的函数
        function dateToDosTime(d) {
            return {
                date: ((d.getFullYear() - 1980) << 9) | ((d.getMonth() + 1) << 5) | d.getDate(),
                time: (d.getHours() << 11) | (d.getMinutes() << 5) | (d.getSeconds() / 2)
            };
        }
 
        const now = new Date();
        const { date: dosDate, time: dosTime } = dateToDosTime(now);
 
        // 将文件添加到ZIP,确保文件名是UTF-8编码
        zipFile.addBuffer(contentBuffer, responsefileName, {
            mtime: now,
            mode: 0o100666, // FAT兼容模式
            compress: true,
            forceZip64Format: false,
            dosPermissions: 0x20, // 设置存档位(普通文件)
            lastModFileTime: dosTime,
            lastModFileDate: dosDate
        });
 
        // 完成ZIP文件并写入输出位置
        const outputZipPath = path.join(location, `${responsezipFileName}`);
        const writeStream = fs.createWriteStream(outputZipPath);
 
        zipFile.outputStream.pipe(writeStream)
            .on('close', () => {
                console.info(`${responsezipFileName} 为FAT系统创建完成。`);
                resolve();
            })
            .on('error', (err) => {
                console.error('创建ZIP文件出错', err);
                reject(err);
            });
 
        zipFile.end();
    }).catch((error) => {
        console.error('test函数内部出错:::', error);
        throw new Error(error.message || '发生未知错误');
    });
}

// 示例调用
test(
    'Downloads',
    '12345',
    `<?xml version="1.0" encoding="UTF-8"?>
    <note>
      <to>John</to>
      <from>Jane</from>
      <heading>Reminder</heading>
      <body>Don't forget the meeting at 10 AM tomorrow!</body>
      <date>2024-09-05</date>
      <unicodeExample>😊</unicodeExample>
    </note>
    `,
    'response.zip',
    'response.xml'
).then(() => {
    console.log('ZIP文件创建成功。');
}).catch((err) => {
    console.error('ZIP文件创建失败:', err);
});

解决方案

要让ZIP压缩包的特性显示为“Descriptor UTF8”,需要同时满足两个核心条件:文件名采用UTF-8编码,并且ZIP条目附带Data Descriptor。以下是具体解决步骤:

1. 升级yazl到最新版本

旧版本的yazl可能存在UTF-8标志与Data Descriptor的兼容问题,先执行升级:

npm update yazl

2. 调整yazl代码配置

你的代码已经开启了UTF-8编码,但需要确保触发Data Descriptor的生成(yazl会在未预先提供文件CRC、压缩大小、未压缩大小的情况下自动生成Data Descriptor),优化后的代码如下:

const yazl = require('yazl');
const fs = require('fs');
const path = require('path');
 
function test(
    location,
    ackId,
    responseContent,
    responsezipFileName,
    responsefileName
) {
    return new Promise((resolve, reject) => {
        // 显式开启UTF-8文件名编码(默认已开启,显式设置更稳妥)
        const zipFile = new yazl.ZipFile({ encodeFileName: true });
 
        const contentBuffer = Buffer.isBuffer(responseContent) ? responseContent : Buffer.from(responseContent, 'utf8');
 
        function dateToDosTime(d) {
            return {
                date: ((d.getFullYear() - 1980) << 9) | ((d.getMonth() + 1) << 5) | d.getDate(),
                time: (d.getHours() << 11) | (d.getMinutes() << 5) | (d.getSeconds() / 2)
            };
        }
 
        const now = new Date();
        const { date: dosDate, time: dosTime } = dateToDosTime(now);
 
        // 不提供crc32、compressedSize、uncompressedSize参数,触发Data Descriptor生成
        zipFile.addBuffer(contentBuffer, responsefileName, {
            mtime: now,
            mode: 0o100666,
            compress: true,
            forceZip64Format: false,
            dosPermissions: 0x20,
            lastModFileTime: dosTime,
            lastModFileDate: dosDate
        });
 
        const outputZipPath = path.join(location, `${responsezipFileName}`);
        const writeStream = fs.createWriteStream(outputZipPath);
 
        zipFile.outputStream.pipe(writeStream)
            .on('close', () => {
                console.info(`${responsezipFileName} 已创建(Descriptor UTF8格式)。`);
                resolve();
            })
            .on('error', (err) => {
                console.error('创建ZIP文件出错', err);
                reject(err);
            });
 
        zipFile.end();
    }).catch((error) => {
        console.error('test函数内部出错:', error);
        throw new Error(error.message || '发生未知错误');
    });
}

// 示例调用同前

3. 备选方案:使用archiver库

如果yazl始终无法达到预期效果,可以尝试archiver库,它支持显式配置Data Descriptor和UTF-8:

const archiver = require('archiver');
const fs = require('fs');
const path = require('path');

function test(location, ackId, responseContent, responsezipFileName, responsefileName) {
    return new Promise((resolve, reject) => {
        const outputPath = path.join(location, responsezipFileName);
        const outputStream = fs.createWriteStream(outputPath);
        // 显式启用UTF-8文件名编码和Data Descriptor
        const archive = archiver('zip', {
            zlib: { level: 9 },
            forceZip64: false,
            utf8: true,
            dataDescriptor: true
        });

        outputStream.on('close', () => {
            console.info(`${responsezipFileName} 创建成功。`);
            resolve();
        });

        archive.on('error', (err) => reject(err));
        archive.pipe(outputStream);

        const contentBuffer = Buffer.isBuffer(responseContent) ? responseContent : Buffer.from(responseContent, 'utf8');
        archive.append(contentBuffer, { name: responsefileName });

        archive.finalize();
    });
}

// 示例调用同前

原理说明

  • UTF-8文件名:通过开启对应配置,让ZIP条目设置通用位标志的第11位,告知解压工具文件名采用UTF-8编码。
  • Data Descriptor:当ZIP条目未预先提供文件校验和与大小信息(yazl),或显式开启配置(archiver)时,会生成Data Descriptor并设置通用位标志的第3位,此时工具就会显示为“Descriptor UTF8”。

内容的提问来源于stack exchange,提问作者Aryan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 16:14:54