Mấy đứa Gen Z mê game, mê lưu thành quả đúng không? Trong lập trình cũng vậy, có lúc mình muốn lưu lại cái gì đó ra file để sau này dùng, hoặc để người khác đọc. Và cái "công cụ" thần thánh mà anh Creyt muốn giới thiệu hôm nay, chính là fs.writeFile() trong Node.js!
1. fs.writeFile() là gì? Để làm gì?
Thử tưởng tượng thế này: code của mấy đứa chạy ầm ầm trên server, xử lý dữ liệu, tính toán tùm lum. Nhưng nếu server reboot cái là mọi thứ bay màu hết à? Xót xa không?
fs.writeFile() (viết tắt của File System Write File) chính là "thư ký" riêng của mấy đứa trong Node.js. Nó nhận nhiệm vụ cực kỳ quan trọng: ghi nội dung vào một file trên ổ đĩa.
Nói nôm na, nó giống như việc mấy đứa đang viết một bức thư tình (dữ liệu), rồi bảo một người đưa thư (Node.js) mang đến một địa chỉ cụ thể (tên file) và đặt nó vào đó. Nếu địa chỉ đó chưa có nhà (file chưa tồn tại), người đưa thư sẽ xây luôn một căn nhà mới rồi đặt thư vào. Còn nếu có nhà rồi, thì xin lỗi chủ nhà cũ nhé, bức thư mới sẽ ghi đè hoàn toàn lên bức thư cũ! Nhớ kỹ cái này nha, ghi đè đó!
Để làm gì á? Đủ thứ trên đời:
- Lưu config của ứng dụng.
- Ghi log lỗi, log hoạt động của hệ thống.
- Tạo file cache để tăng tốc độ.
- Xuất báo cáo, invoice dưới dạng file text, JSON, CSV...
- Lưu trữ dữ liệu đơn giản mà không cần database phức tạp.
2. Code Ví Dụ Minh Họa Rõ Ràng (Tối Giản nhưng Chuẩn Kiến Thức)
Ok, lý thuyết đủ rồi, giờ mình đi vào thực hành "thư ký" này làm việc nhé.
Cú pháp cơ bản: fs.writeFile(path, data, [options], callback) hoặc dùng Promise (async/await) cho xịn.
Ví dụ 1: Ghi file đơn giản với Callback (kiểu cũ nhưng vẫn dùng được):
const fs = require('fs');
const tenFile = 'thong_diep_cua_creyt.txt';
const noiDung = 'Chào các bạn Gen Z! Đây là thông điệp bí mật từ Creyt. Học Node.js vui vẻ nhé!';
fs.writeFile(tenFile, noiDung, (err) => {
if (err) {
console.error('Ối giời ơi, có lỗi rồi Creyt ơi:', err);
return;
}
console.log(`Đã ghi thành công vào file: ${tenFile}`);
});
Ví dụ 2: Ghi file với Promise/Async-Await (chuẩn Gen Z, hiện đại hơn):
const fs = require('fs').promises; // Dùng phiên bản promise của fs
async function ghiThongDiepMoi() {
const tenFile = 'thong_diep_moi_cua_creyt.json';
const duLieuJSON = {
tacGia: 'Creyt',
tieuDe: 'Hướng dẫn fs.writeFile()',
noiDung: 'Node.js thật bá đạo!',
version: '1.0.0'
};
try {
await fs.writeFile(tenFile, JSON.stringify(duLieuJSON, null, 2), 'utf8');
console.log(`Đã ghi thành công file JSON: ${tenFile}`);
} catch (err) {
console.error('Lỗi khi ghi file JSON:', err);
}
}
ghiThongDiepMoi();
Giải thích nhẹ:
JSON.stringify(duLieuJSON, null, 2): Cái này để biến object JavaScript thành chuỗi JSON.null, 2là để format cho dễ đọc, mỗi cấp thụt vào 2 khoảng trắng.'utf8': Là kiểu mã hóa, hầu như luôn dùng cái này cho tiếng Việt và các ký tự đặc biệt.

3. Vài Mẹo Hay Của Creyt (Best Practices) Để Ghi Nhớ và Dùng Thực Tế
- Luôn Luôn Xử Lý Lỗi (Error Handling): Đây là điều tiên quyết! Giống như lái xe phải thắt dây an toàn vậy. Mấy đứa luôn phải kiểm tra
errtrong callback hoặc dùngtry...catchvớiasync/await. Nếu không, ứng dụng có thể "chết lâm sàng" mà mấy đứa không biết tại sao. - Hiểu Rõ Tính Bất Đồng Bộ (Asynchronous Nature):
fs.writeFile()là hàm bất đồng bộ. Tức là nó sẽ "giao việc" cho hệ điều hành rồi đi làm việc khác ngay, không chờ đợi. Khi nào ghi xong hoặc có lỗi thì nó mới gọi lại callback hoặc resolve/reject Promise. Đừng bao giờ nghĩ nó chạy xong rồi mới chạy dòng code tiếp theo nhé! writeFilevsappendFile: Nhớ cái vụ "ghi đè" ban nãy không?fs.writeFile()là ghi đè toàn bộ. Nếu mấy đứa chỉ muốn thêm nội dung vào cuối file mà không mất dữ liệu cũ, hãy dùngfs.appendFile(). Giống như viết thêm vào cuối nhật ký thay vì xé trang cũ viết lại vậy.- Encoding: Mặc định là
utf8, rất tốt cho tiếng Việt. Nếu mấy đứa làm việc với các hệ thống cũ hoặc file đặc thù, có thể cần chỉ định encoding khác (ví dụ:'latin1'). - Quyền Ghi File (Permissions): Đôi khi, Node.js không có quyền ghi vào một thư mục nào đó. Lúc đó,
fs.writeFile()sẽ báo lỗiEACCES(Permission denied). Hãy kiểm tra lại quyền của thư mục mà mấy đứa đang cố gắng ghi file vào.
4. Học Thuật Sâu Của Anh Creyt: "Thư Ký" Làm Việc Thế Nào?
Mấy đứa có bao giờ tự hỏi, tại sao Node.js lại nhanh đến vậy không? Một phần là nhờ vào cái "bất đồng bộ" mà anh vừa nói đấy.
Khi mấy đứa gọi fs.writeFile(), Node.js không tự mình đi ghi file đâu. Nó sẽ "ủy quyền" việc này cho hệ điều hành (OS) thông qua một cái gọi là thread pool (một nhóm các "công nhân" chuyên làm việc nặng).
Cái thread pool này sẽ thực hiện việc ghi file lên ổ đĩa. Trong lúc đó, Node.js (cái "luồng chính" hay còn gọi là Event Loop) vẫn rảnh rang xử lý các yêu cầu khác, ví dụ như nhận request từ người dùng, tính toán...
Khi hệ điều hành ghi file xong (thành công hay thất bại), nó sẽ báo lại cho Node.js, và Node.js sẽ kích hoạt callback hoặc xử lý Promise.
Chính cơ chế này giúp ứng dụng Node.js của mấy đứa không bị "đứng hình" (blocking) khi phải chờ đợi các thao tác I/O (Input/Output) chậm chạp như ghi/đọc file hay gọi database. Nghe có vẻ phức tạp nhưng hiểu được nó, mấy đứa sẽ thấy Node.js cực kỳ mạnh mẽ!
5. Ví Dụ Thực Tế Các Ứng Dụng/Website Đã Ứng Dụng
- Hệ thống Log: Hầu hết các ứng dụng backend, từ app nhỏ đến hệ thống lớn, đều dùng
fs.writeFile()(hoặc các thư viện dựa trên nó) để ghi lại nhật ký hoạt động, lỗi, cảnh báo vào các file log. Ví dụ:access.log,error.log. - Cache Dữ Liệu: Một số trang web hoặc API server dùng
fs.writeFile()để lưu trữ các phản hồi API thường xuyên được truy cập vào file tạm thời. Lần sau có yêu cầu tương tự, chỉ cần đọc file cache ra trả về, không cần gọi database, giúp tăng tốc độ "thần chưởng". - Xuất Báo Cáo/Dữ Liệu: Khi mấy đứa nhấn nút "Export to CSV" hay "Download Report" trên các dashboard quản lý, rất có thể backend đã dùng
fs.writeFile()để tạo ra file đó rồi gửi về cho mấy đứa. - Cấu hình Ứng Dụng: Các file cấu hình như
.env,config.jsonđôi khi được tạo hoặc cập nhật tự động bởi các script Node.js dùngfs.writeFile().
6. Thử Nghiệm Đã Từng và Hướng Dẫn Nên Dùng Cho Case Nào
- Creyt đã từng thử nghiệm: Hồi xưa, anh từng làm một cái "hệ thống" nhỏ tự động crawl dữ liệu từ vài trang web, sau đó dùng
fs.writeFile()để lưu trữ từng mẩu tin vào các file JSON riêng biệt. Sau đó thì có một script khác đọc các file JSON đó lên để xử lý. Nó chạy ngon lành cho dữ liệu nhỏ và vừa. - Nên dùng cho:
- Ghi log: Tuyệt vời để ghi nhật ký, thông báo lỗi.
- Lưu trữ cấu hình: Các file cấu hình nhỏ, ít thay đổi.
- Tạo file tạm thời: Cache, báo cáo, file xuất dữ liệu một lần.
- Lưu trữ dữ liệu nhỏ, đơn giản: Ví dụ, lưu thông tin điểm số của một game offline đơn giản, lưu danh sách việc cần làm (todo list) của một ứng dụng desktop.
- KHÔNG nên dùng cho:
- Database chính thức: Đừng bao giờ nghĩ
fs.writeFile()có thể thay thế một database chuyên nghiệp như MySQL, PostgreSQL, MongoDB nhé. Khi dữ liệu lớn, cần truy vấn phức tạp, quan hệ, bảo mật, tính toàn vẹn, đa người dùng truy cập cùng lúc, thì file system không đủ sức đâu. - Ghi file liên tục, tốc độ cao với nhiều luồng: Nếu có hàng trăm, hàng nghìn yêu cầu ghi file cùng lúc, việc quản lý race condition (khi nhiều tác vụ cố gắng ghi vào cùng một file) sẽ rất phức tạp và dễ gây lỗi, hỏng dữ liệu. Lúc đó cần các giải pháp queuing hoặc database chuyên dụng.
- Database chính thức: Đừng bao giờ nghĩ
Thấy không, fs.writeFile() tuy đơn giản nhưng lại là một "thư ký" cực kỳ đắc lực trong Node.js, giúp mấy đứa Gen Z lưu trữ và quản lý dữ liệu một cách hiệu quả. Nắm vững nó, mấy đứa sẽ có thêm một công cụ mạnh mẽ trong bộ đồ nghề lập trình của mình đấy! Chúc mấy đứa code vui vẻ!
Thuộc Series: Nodejs
Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!