Node.js 小工具

[UPDATE] 之前的版本不能壓縮資料夾,用 ChatGPT 再修改一下….

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

const archiver = require('archiver');
const ftpClient = require('ftp');
const nodemailer = require('nodemailer');

const toUser = '[email protected]';
let fileSize;

// 取得 .zip 檔名,預設為:YYYYMMDD-HHMMSS
const zipFileName = process.argv[2] || getDateTime();

if (!checkFileName(zipFileName)) {
  console.error('檔名輸入有誤!!');
  return false;
}

// input_files 資料夾
const inputDir = path.join(__dirname, 'input_files');

// 確認 output_zip 資料夾是否存在,若不存在則建立
const outputDir = path.join(__dirname, 'output_zip');

if (!fs.existsSync(outputDir)) {
  fs.mkdirSync(outputDir);
}

// 建立一個輸出檔案流,指定存放在 output_zip 資料夾下
const outputFilePath = path.join(outputDir, `${zipFileName}.zip`);

// 壓縮
zipDirectory(inputDir, outputFilePath);

// --- function ---
function formatBytes(bytes) {
  if (bytes === 0) {
    return '0 Bytes';
  }

  const k = 1024;
  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];

  const i = Math.floor(Math.log(bytes) / Math.log(k));

  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}

function getDateTime() {
  let today = new Date();

  let year = today.getFullYear();
  let month = ('0' + (today.getMonth() + 1)).slice(-2);
  let date = ('0' + today.getDate()).slice(-2);

  let hours = ('0' + today.getHours()).slice(-2);
  let minutes = ('0' + today.getMinutes()).slice(-2);
  let seconds = ('0' + today.getSeconds()).slice(-2);

  return `${year}${month}${date}-${hours}${minutes}${seconds}`;
}

function checkFileName(fileName) {
  const regex = /^[a-zA-Z0-9_-]+$/;
  return regex.test(fileName);
}

function zipDirectory(sourceDir, outPath) {
  const output = fs.createWriteStream(outPath);

  const archive = archiver('zip', {
    zlib: { level: 9 } // 設定壓縮等級 (1-9)
  });

  // 開始壓縮
  archive.pipe(output);
  archive.directory(sourceDir, false); // 將資料夾的內容添加至壓縮檔
  archive.finalize();

  output.on('close', () => {
    fileSize = formatBytes(archive.pointer());

    console.log(`[${zipFileName}.zip] 壓縮完成,總共 ${fileSize}`);

    // 壓縮完成後上傳到 FTP 伺服器
    uploadFileToFtp();
  });

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

function uploadFileToFtp() {
  const client = new ftpClient();

  client.on('ready', () => {
    client.put(
      outputFilePath,
      `/downloads/${zipFileName}.zip`,
      (err) => {
        if (err) {
          throw err;
        }

        console.log('檔案上傳完成 OK');
        client.end();

        // 發送電子郵件通知
        sendEmail();
      }
    );
  });

  client.on('error', (err) => {
    console.error('FTP 連接錯誤:', err);
  });

  // 連接到 FTP 伺服器
  client.connect({
    host: '100.100.100.100',
    user: 'user',
    password: 'password',
  });
}

function sendEmail() {
  const transporter = nodemailer.createTransport({
    host: 'smtp.office365.com',
    port: 587,
    secure: false, // true for 465, false for other ports
    auth: {
      user: 'user',
      pass: 'pass',
    },
  });

  const mailOptions = {
    from: '"SYSTEM" <[email protected]>',
    to: toUser,
    subject: `${zipFileName}.zip`,
    text: `File Size: ${fileSize}\nhttps://www.abc.com.tw/downloads/${zipFileName}.zip`,
  };

  transporter.sendMail(mailOptions, (err) => {
    if (err) {
      console.error('電子郵件發送失敗:', err);
      return false;
    }

    console.log('電子郵件發送成功 OK');
  });
}

這個小工具可以把特定資料夾內的檔案壓縮成一個 .zip 檔,再把 .zip 檔上傳到 FTP Server,上傳成功後會發送通知 Email。

有用到 archiverftpnodemailer 三個 package。

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

const archiver = require('archiver');
const ftpClient = require('ftp');
const nodemailer = require('nodemailer');

const toUser = '[email protected]'; // 要收到通知的 user
let fileSize;

const archive = archiver('zip', {
  zlib: { level: 9 }, // 設定壓縮等級
});

// 取得 .zip 檔名,預設為:YYYYMMDD-HHMMSS
const zipFileName = process.argv[2] || getDateTime();

if (!checkFileName(zipFileName)) {
  console.error('檔名輸入有誤!!');
  return false;
}

// 確認 output_zip 資料夾是否存在,若不存在則建立
const outputDir = path.join(__dirname, 'output_zip');

if (!fs.existsSync(outputDir)) {
  fs.mkdirSync(outputDir);
}

// 建立一個輸出檔案流,指定存放在 output_zip 資料夾下
const outputFilePath = path.join(outputDir, `${zipFileName}.zip`);

const output = fs.createWriteStream(outputFilePath);

// 連結檔案流至壓縮檔
archive.pipe(output);

// 獲取 input_files 資料夾中的所有檔案
const inputDir = path.join(__dirname, 'input_files');

fs.readdir(inputDir, (err, files) => {
  if (err) {
    throw err;
  }

  let count = 0;

  // 使用 for 迴圈添加每個檔案至壓縮檔
  for (const file of files) {
    const filePath = path.join(inputDir, file);

    archive.file(filePath, { name: file });
    console.log(`[${file}] 加入壓縮檔....`);

    count++;
  }

  console.log(`共 [${count}] 個檔案加入`);

  // 完成壓縮檔案
  archive.finalize();
});

output.on('close', () => {
  fileSize = formatBytes(archive.pointer());

  console.log(`[${zipFileName}.zip] 壓縮完成,總共 ${fileSize}`);

  // 壓縮完成後上傳到 FTP 伺服器
  uploadFileToFtp();
});

archive.on('warning', (err) => {
  if (err.code !== 'ENOENT') {
    throw err;
  }
});

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

// --- function ---
function formatBytes(bytes) {
  if (bytes === 0) {
    return '0 Bytes';
  }

  const k = 1024;
  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];

  const i = Math.floor(Math.log(bytes) / Math.log(k));

  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}

function getDateTime() {
  let today = new Date();

  let year = today.getFullYear();
  let month = ('0' + (today.getMonth() + 1)).slice(-2);
  let date = ('0' + today.getDate()).slice(-2);

  let hours = ('0' + today.getHours()).slice(-2);
  let minutes = ('0' + today.getMinutes()).slice(-2);
  let seconds = ('0' + today.getSeconds()).slice(-2);

  return `${year}${month}${date}-${hours}${minutes}${seconds}`;
}

function checkFileName(fileName) {
  const regex = /^[a-zA-Z0-9_-]+$/;
  return regex.test(fileName);
}

function uploadFileToFtp() {
  const client = new ftpClient();

  client.on('ready', () => {
    client.put(
      outputFilePath,
      `/downloads/${zipFileName}.zip`,
      (err) => {
        if (err) {
          throw err;
        }

        console.log('檔案上傳完成 OK');
        client.end();

        // 發送電子郵件通知
        sendEmail();
      }
    );
  });

  client.on('error', (err) => {
    console.error('FTP 連接錯誤:', err);
  });

  // 連接到 FTP 伺服器
  client.connect({
    host: '100.100.100.100',
    user: 'user',
    password: 'password',
  });
}

function sendEmail() {
  const transporter = nodemailer.createTransport({
    host: 'smtp.office365.com',
    port: 587,
    secure: false, // true for 465, false for other ports
    auth: {
      user: 'user',
      pass: 'pass',
    },
  });

  const mailOptions = {
    from: '"SYSTEM" <[email protected]>',
    to: toUser,
    subject: `${zipFileName}.zip`,
    text: `File Size: ${fileSize}\nhttps://www.abc.com.tw/downloads/${zipFileName}.zip`,
  };

  transporter.sendMail(mailOptions, (err) => {
    if (err) {
      console.error('電子郵件發送失敗:', err);
      return false;
    }

    console.log('電子郵件發送成功 OK');
  });
}

Download

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

返回頂端