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。
有用到 archiver、ftp、nodemailer 三個 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');
});
}