Zip files và gửi vể client trong Expressjs. Không làm vỡ font khi giải nén file (Dùng với phần mềm Lhaplus)

Hiện tại việc zip file và gửi về client trong Expressjs thì có rất nhiều tài liệu trên mạng.

Tuy nhiên, có một vấn đề khi giải nén đó là lỗi font tên file hay tên thư mục (tên file và tên thư mục dùng ký tự không phải unicode). Đặc biệt dùng phần mềm Lhaplus - phần mềm phổ biến nén và giải nén trên window của người Nhật.

 

Trong bài viết này mình sẽ dùng package JSZip (https://www.npmjs.com/package/jszip) để thực hiện việc nén file text có dung lượng lớn (các log file).

 

Đọc file ra buffer (cách này thực hiện để đọc file dung lượng lớn):

const readFile = async function (filePath) {
  // const fs = require('fs');
  // const es = require('event-stream');
  let buffers = [];
  return new Promise((resolve, reject) => {
    let s = fs.createReadStream(filePath)
      .pipe(es.split())
      .pipe(es.mapSync(function (line) {
        buffers.push(Buffer.from(line + '\n'));
      }).on('error', function (err) {
        console.log('Error while reading file.', err);
      }).on('end', function () {
        console.log('Read entire file. ');
        resolve(Buffer.concat(buffers));
      })
      );
  });
}

Zip file:

const jszipFn = async function (filePaths) {
  let zip = new JSZip();
  for(let i = 0; i < filePaths.length; i++) {
    let zupSubDirName = `例題${i}`;
    let zipSubDir = zip.folder(zupSubDirName);
    let buffer = await readFile(filePaths[i]);
    zipSubDir.file(`${zupSubDirName}.log`, buffer);
  }

  let zipBuffer await zip.generateAsync({ 
    type: "nodebuffer",
    // compression zip file, 
    // if don't use this option zip file will be not compressed
    compression: "DEFLATE", 
    // iconv = require('iconv-lite');
    // the option to fix break font when extract zip file
    encodeFileName: fileName => iconv.encode(fileName, "CP932")
  });
  let zipFilePath = proccess.cwd() + '/zipFile.zip'
  fs.writeFileSync(zipFilePath, zipBuffer);
  return zipFilePath;
}

 

Send file to client:

app.post('/jszip', async function (req, res) {
  // In case zip file so large, increase timeout
  // req.setTimeout(500000);
  let filePaths = ...;
  let zipFile = await jszipFn(filePaths);
  if(fs.existsSync(zipFile)) {
      let fileZipName = '例題.zip';
      res.download(zipFile, fileZipName, function(err){
        fs.unlinkSync(zipFile);
        res.end();
      });
  } else {
      res.redirect('/jszip');
  }
});

Leave a Comment

Fields with * are required.