Bài 3. Tệp tin, đường dẫn, biến môi trường và process

Bài này học các mô-đun lõi dùng hằng ngày: đọc ghi tệp và thư mục với node:fs/promises, xử lý đường dẫn đa nền tảng với node:path, đối tượng process, tham số dòng lệnh và biến môi trường để giữ bí mật cấu hình.

45 phútCơ bản
Bạn sẽ học được
  • Đọc, ghi, nối, xóa tệp; làm việc với thư mục
  • Ghép đường dẫn an toàn với path, import.meta.dirname
  • Dùng process.argv, process.env, process.exit
  • Nạp tệp .env bằng --env-file

Một số khái niệm

Luôn dùng phiên bản Promise (node:fs/promises) với async/await thay vì hàm đồng bộ (readFileSync) trong máy chủ, vì hàm đồng bộ chặn mọi yêu cầu khác. Thông tin bí mật (mật khẩu CSDL, khóa API) đặt trong biến môi trường, không ghi vào mã.

Tệp và thư mục

import { readFile, writeFile, appendFile, mkdir, readdir, rm, stat } from 'node:fs/promises';
import path from 'node:path';

const thuMuc = path.join(import.meta.dirname, 'data');
await mkdir(thuMuc, { recursive: true });

const tep = path.join(thuMuc, 'sinhvien.json');
await writeFile(tep, JSON.stringify([{ ma: 'SV001', ten: 'Lò Văn An' }], null, 2));
const ds = JSON.parse(await readFile(tep, 'utf8'));
ds.push({ ma: 'SV002', ten: 'Cầm Thị Bình' });
await writeFile(tep, JSON.stringify(ds, null, 2));

await appendFile(path.join(thuMuc, 'nhat-ky.log'), `${new Date().toISOString()} Đã thêm SV002\n`);
for (const ten of await readdir(thuMuc)) {
  const s = await stat(path.join(thuMuc, ten));
  console.log(ten, s.size, 'byte');
}

path.join tự dùng đúng dấu phân cách (\ trên Windows, / trên macOS/Linux); import.meta.dirname là thư mục chứa tệp hiện tại.

Biến môi trường và .env

# .env (thêm vào .gitignore)
PORT=3000
DB_HOST=localhost
DB_USER=root
DB_PASS=
DB_NAME=qlsv
JWT_SECRET=chuoi-bi-mat-dai-ngau-nhien
// server.js
const port = Number(process.env.PORT ?? 3000);
if (!process.env.JWT_SECRET) {
  console.error('Thiếu JWT_SECRET'); process.exit(1);
}
node --env-file=.env server.js      # Node.js nạp .env, không cần gói dotenv

process và tham số dòng lệnh

// doi-ten.js: node doi-ten.js ./anh .jpg
import { parseArgs } from 'node:util';
const { positionals, values } = parseArgs({ allowPositionals: true, options: { 'thu': { type: 'boolean' } } });
const [thuMuc = '.', duoi = '.jpg'] = positionals;
console.log('Thư mục:', thuMuc, 'đuôi:', duoi, 'chạy thử:', values.thu ?? false);
console.log('Bộ nhớ đang dùng:', Math.round(process.memoryUsage().rss / 1e6), 'MB');
process.on('SIGINT', () => { console.log('Đã dừng'); process.exit(0); });
Mẹo hay

Tạo tệp .env.example liệt kê tên biến (không có giá trị thật) và commit lên Git để đồng đội biết cần cấu hình gì.

Lưu ý

Nối đường dẫn từ dữ liệu người dùng (tên tệp tải lên, tham số URL) có thể bị tấn công path traversal (../../etc/passwd); luôn kiểm tra kết quả nằm trong thư mục cho phép.

Thực hành
  1. Viết công cụ đổi tên hàng loạt ảnh trong thư mục theo ngày.
  2. Lưu danh sách sinh viên vào tệp JSON, thêm và xóa phần tử.
  3. Ghi nhật ký mỗi lần chạy chương trình.
  4. Đọc cấu hình cổng, CSDL từ .env bằng --env-file.
Tóm tắt bài học
  • node:fs/promises + async/await cho tệp, thư mục.
  • path.join, import.meta.dirname cho đường dẫn.
  • process.env + --env-file cho bí mật; .env vào .gitignore.
  • process.argv, util.parseArgs cho công cụ dòng lệnh.