Cách làm việc với tệp bằng module fs trong Node.js
Làm việc với các file là phổ biến cho các mục đích phát triển cũng như cho các mục đích không phát triển. Trong việc sử dụng máy tính hàng ngày, user có thể đọc và ghi dữ liệu vào các file trong các folder khác nhau để thực hiện các việc như lưu file đã download hoặc truy cập dữ liệu để sử dụng trong ứng dụng khác. Theo cách tương tự, chương trình back-end hoặc công cụ giao diện dòng lệnh (CLI) có thể cần ghi dữ liệu đã download vào file để lưu file đó hoặc một ứng dụng sử dụng nhiều dữ liệu có thể cần xuất sang JSON , CSV hoặc Excel các định dạng. Các chương trình này cần giao tiếp với hệ thống file của hệ điều hành mà chúng đang chạy. Với Node.js , bạn có thể lập trình thao tác các file  với mô-đun fs . Tên viết tắt của “hệ thống file ” và module  chứa tất cả các chức năng bạn cần để đọc, ghi và xóa file  trên máy local . Khía cạnh độc đáo này của Node.js làm cho JavaScript trở thành ngôn ngữ hữu ích cho lập trình công cụ back-end và CLI.
 Trong bài viết này, bạn sẽ sử dụng module  fs để đọc file  được tạo qua dòng lệnh, tạo và ghi vào file  mới, xóa file  mà bạn đã tạo và di chuyển file  đầu tiên vào một folder  khác. Mô-đun fs hỗ trợ tương tác với các file  một cách đồng bộ, không đồng bộ hoặc qua các stream ; hướng dẫn này sẽ tập trung vào cách sử dụng API không đồng bộ, dựa trên Promise , phương pháp được sử dụng phổ biến nhất cho các nhà phát triển Node.js.
Yêu cầu
- Bạn phải cài đặt Node.js trên máy tính của bạn để truy cập vào module - fsvà làm theo hướng dẫn. Hướng dẫn này sử dụng Node.js version 10.22.0. Để cài đặt Node.js trên macOS hoặc Ubuntu 18.04, hãy làm theo các bước trong Cách cài đặt Node.js và Tạo môi trường phát triển local trên macOS hoặc phần Cài đặt bằng PPA của Cách cài đặt Node.js trên Ubuntu 18.04 .
- Bài viết này sử dụng JavaScript Promises để làm việc với các file , đặc biệt là với cú pháp - async/await. Nếu bạn không quen với Promises, cú pháp- async/awaithoặc lập trình không đồng bộ, hãy xem hướng dẫn của ta về Cách viết mã không đồng bộ trong Node.js.
 Bước 1 - Đọc file  với readFile()
 Trong bước này, bạn sẽ viết một chương trình để đọc các file  trong Node.js. Để thực hiện việc này, bạn  cần  nhập module  fs , một module  Node.js tiêu chuẩn để làm việc với các file , sau đó sử dụng hàm readFile() của module . Chương trình của bạn sẽ đọc file , lưu trữ nội dung của nó trong một biến, sau đó ghi nội dung của nó vào console .
Bước đầu tiên sẽ là cài đặt môi trường mã hóa cho hoạt động này và những môi trường trong các phần sau.
 Tạo một folder  để lưu trữ mã của bạn. Trong terminal  của bạn, hãy tạo một folder  có tên là node-files :
- mkdir node-files 
Thay đổi folder  làm việc của bạn thành folder  mới được tạo bằng lệnh cd :
- cd node-files 
Trong folder này, bạn sẽ tạo hai file . Tệp đầu tiên sẽ là một file mới có nội dung mà chương trình của bạn sẽ đọc sau này. Tệp thứ hai sẽ là module Node.js đọc file .
 Tạo file  greetings.txt bằng lệnh sau:
- echo "hello, hola, bonjour, hallo" > greetings.txt 
Lệnh echo in đối số chuỗi của nó tới terminal. Bạn sử dụng > để chuyển hướng  kết quả  của echo đến một file  mới, greetings.txt .
 Bây giờ, hãy tạo và mở readFile.js trong editor  mà bạn chọn. Hướng dẫn này sử dụng nano , một editor   terminal . Bạn có thể mở file  này bằng nano như sau:
- nano readFile.js 
Mã cho file này có thể được chia thành ba phần. Trước tiên, bạn cần nhập mô-đun Node.js cho phép chương trình của bạn hoạt động với các file . Trong editor của bạn, hãy nhập mã này:
const fs = require('fs').promises; Như đã đề cập trước đó, bạn sử dụng module  fs để tương tác với hệ thống file . Tuy nhiên, hãy  lưu ý  bạn đang nhập phần .promises của module .
 Khi module  fs lần đầu tiên được tạo, cách chính để viết mã không đồng bộ trong Node.js là thông qua các lệnh gọi lại . Khi những lời hứa ngày càng trở nên phổ biến,  group  Node.js đã làm việc để hỗ trợ chúng trong module  fs ra khỏi hộp. Trong version  Node.js 10, họ đã tạo một đối tượng promises trong module  fs sử dụng các lời hứa, trong khi module  fs chính tiếp tục hiển thị các hàm sử dụng lệnh gọi lại. Trong chương trình này, bạn đang nhập version  hứa hẹn của module .
 Sau khi module  được nhập, bạn có thể tạo một hàm không đồng bộ để đọc file . Các hàm không đồng bộ bắt đầu bằng từ khóa async . Với một hàm không đồng bộ, bạn có thể giải quyết các lời hứa bằng cách sử dụng từ khóa await , thay vì xâu chuỗi lời hứa bằng phương thức .then() .
 Tạo một hàm mới readFile() chấp nhận một đối số, một chuỗi được gọi là filePath . Hàm readFile() của bạn sẽ sử dụng module  fs để tải file  vào một biến bằng cách sử dụng cú pháp async/await .
Nhập mã được đánh dấu sau:
const fs = require('fs').promises;  async function readFile(filePath) {   try {     const data = await fs.readFile(filePath);     console.log(data.toString());   } catch (error) {     console.error(`Got an error trying to read the file: ${error.message}`);   } } Bạn xác định hàm với từ khóa async để sau này bạn có thể sử dụng từ khóa await đi kèm. Để ghi lại lỗi trong thao tác đọc file  không đồng bộ của bạn, bạn gửi lời gọi tới fs.readFile() bằng một khối try...catch . Trong phần try , bạn tải file  vào biến data bằng hàm fs.readFile() . Đối số bắt buộc duy nhất cho hàm đó là đường dẫn file , được cung cấp dưới dạng một chuỗi.
 Theo mặc định, fs.readFile() trả về một đối tượng buffer . Đối tượng buffer có thể lưu trữ bất kỳ loại file  nào. Khi bạn đăng nhập nội dung của file , bạn chuyển đổi các byte đó thành văn bản bằng cách sử dụng phương thức toString() của đối tượng đệm.
Nếu gặp lỗi, thường là nếu không tìm thấy file hoặc chương trình không có quyền đọc file , bạn ghi lại lỗi bạn nhận được trong console .
 Cuối cùng, hãy gọi hàm trên file  greetings.txt với dòng được đánh dấu sau:
const fs = require('fs').promises;  async function readFile(filePath) {   try {     const data = await fs.readFile(filePath);     console.log(data.toString());   } catch (error) {     console.error(`Got an error trying to read the file: ${error.message}`);   } }  readFile('greetings.txt'); Hãy chắc chắn để lưu nội dung của bạn. Với nano , bạn có thể lưu và thoát bằng cách nhấn CTRL+X
 Chương trình của bạn bây giờ sẽ đọc file  tin greetings.txt mà bạn đã tạo trước đó và đăng nhập nội dung của nó vào terminal . Xác nhận điều này bằng cách thực thi module  của bạn với node :
- node readFile.js 
Bạn sẽ nhận được kết quả sau:
Outputhello, hola, bonjour, hallo  Đến đây bạn  đã đọc một file  với hàm readFile() của module  fs bằng cách sử dụng cú pháp async/await .
 Lưu ý: Trong một số version  trước đó của Node.js, bạn sẽ nhận được cảnh báo sau khi sử dụng module  fs :
(node:13085) ExperimentalWarning: The fs.promises API is experimental Đối tượng promises của module  fs đã được giới thiệu trong version  Node.js 10, vì vậy một số version  trước đó vẫn gọi module  là thử nghiệm. Cảnh báo này đã bị xóa khi API trở nên ổn định trong version  12.6.
  Đến đây bạn  đã đọc một file  với module  fs , tiếp theo bạn sẽ tạo một file  và ghi văn bản vào đó.
 Bước 2 - Viết file  bằng writeFile()
 Trong bước này, bạn sẽ ghi file  bằng hàm writeFile() của module  fs . Bạn sẽ tạo một file  CSV trong Node.js để theo dõi hóa đơn hàng tạp hóa. Lần đầu tiên bạn ghi file , bạn sẽ tạo file  và thêm các tiêu đề. Lần thứ hai, bạn sẽ nối dữ liệu vào file .
Mở một file mới trong editor của bạn:
- nano writeFile.js 
Bắt đầu mã của bạn  bằng lệnh  module  fs :
const fs = require('fs').promises; Bạn sẽ tiếp tục sử dụng cú pháp async/await khi bạn tạo hai hàm. Chức năng đầu tiên sẽ là tạo file  CSV. Chức năng thứ hai sẽ là thêm dữ liệu vào file  CSV.
Trong editor của bạn, hãy nhập mã được đánh dấu sau:
const fs = require('fs').promises;  async function openFile() {   try {     const csvHeaders = 'name,quantity,price'     await fs.writeFile('groceries.csv', csvHeaders);   } catch (error) {     console.error(`Got an error trying to write to a file: ${error.message}`);   } } Trước tiên, hàm không đồng bộ này tạo một biến csvHeaders chứa các tiêu đề cột của file  CSV của bạn. Sau đó, bạn sử dụng hàm writeFile() của module  fs để tạo file  và ghi dữ liệu vào đó. Đối số đầu tiên là đường dẫn file . Khi bạn chỉ cung cấp tên file , Node.js sẽ tạo file  trong cùng folder  mà bạn đang thực thi mã. Đối số thứ hai là dữ liệu bạn đang ghi, trong trường hợp này là biến csvHeaders .
Tiếp theo, tạo một chức năng mới để thêm các mặt hàng vào danh sách tạp hóa của bạn. Thêm chức năng được đánh dấu sau vào editor của bạn:
const fs = require('fs').promises;  async function openFile() {   try {     const csvHeaders = 'name,quantity,price'     await fs.writeFile('groceries.csv', csvHeaders);   } catch (error) {     console.error(`Got an error trying to write to a file: ${error.message}`);   } }  async function addGroceryItem(name, quantity, price) {   try {     const csvLine = `\n${name},${quantity},${price}`     await fs.writeFile('groceries.csv', csvLine, { flag: 'a' });   } catch (error) {     console.error(`Got an error trying to write to a file: ${error.message}`);   } } Hàm addGroceryItem() không đồng bộ chấp nhận ba đối số: tên của mặt hàng tạp hóa, số lượng bạn đang mua và giá mỗi đơn vị. Các đối số này được sử dụng với cú pháp chữ mẫu để tạo thành biến csvLine , là dữ liệu bạn đang ghi vào file .
 Sau đó, bạn sử dụng phương thức writeFile() như bạn đã làm trong hàm openFile() . Tuy nhiên, lần này bạn có đối số thứ ba: một đối tượng JavaScript . Đối tượng này có một khóa flag với giá trị a . Các cờ cho Node.js biết cách tương tác với file  trên hệ thống. Bằng cách sử dụng cờ a , bạn đang yêu cầu Node.js nối thêm vào file , không overrides  lên file . Nếu bạn không chỉ định cờ, nó sẽ mặc định là w , sẽ tạo một file  mới nếu không có hoặc overrides  lên một file  nếu nó đã tồn tại. Bạn có thể tìm hiểu thêm về cờ hệ thống file  trong tài liệu Node.js.
Để hoàn thành tập lệnh của bạn, hãy sử dụng các chức năng này. Thêm các dòng được đánh dấu sau vào cuối file :
... async function addGroceryItem(name, quantity, price) {   try {     const csvLine = `\n${name},${quantity},${price}`     await fs.writeFile('groceries.csv', csvLine, { flag: 'a' });   } catch (error) {     console.error(`Got an error trying to write to a file: ${error.message}`);   } }  (async function () {   await openFile();   await addGroceryItem('eggs', 12, 1.50);   await addGroceryItem('nutella', 1, 4); })(); Để gọi các hàm, trước tiên bạn tạo một hàm wrapper với async function . Kể từ khi await từ khóa không thể được sử dụng từ phạm vi  global  như các văn bản của hướng dẫn này, bạn phải quấn các chức năng không đồng bộ trong một async function .  Lưu ý  chức năng này là ẩn danh,  nghĩa là  nó không có tên để xác định nó.
 Các openFile() và addGroceryItem() là các hàm không đồng bộ. Nếu không đặt các lệnh gọi này trong một hàm khác, bạn không thể đảm bảo thứ tự của nội dung. Các wrapper bạn đã tạo được định nghĩa với async từ khóa. Trong hàm đó, bạn sắp xếp các lệnh gọi hàm bằng cách sử dụng từ khóa await .
 Cuối cùng, định nghĩa async function được đặt trong dấu ngoặc đơn. Chúng cho JavaScript biết rằng mã bên trong chúng là một biểu thức hàm. Dấu ngoặc đơn ở cuối hàm và trước dấu chấm phẩy được sử dụng để gọi hàm ngay lập tức. Đây được gọi là Biểu thức hàm được gọi ngay lập tức (IIFE) . Bằng cách sử dụng IIFE với chức năng ẩn danh, bạn có thể kiểm tra xem mã  của bạn  có tạo ra file  CSV có ba dòng: tiêu đề cột, một dòng cho eggs và dòng cuối cùng cho nutella .
 Lưu và thoát nano bằng CTRL+X
 Bây giờ, hãy chạy mã của bạn bằng lệnh node :
- node writeFile.js 
Sẽ không có kết quả . Tuy nhiên, một file mới sẽ tồn tại trong folder hiện tại của bạn.
 Sử dụng lệnh cat để hiển thị nội dung của groceries.csv :
- cat groceries.csv 
Bạn sẽ nhận được kết quả sau:
name,quantity,price eggs,12,1.5 nutella,1,4 openFile() gọi openFile() đã tạo một file  mới và thêm các tiêu đề cột cho CSV của bạn. Các cuộc gọi tiếp theo tới addGroceryItem() sau đó đã thêm hai dòng  dữ liệu .
 Với hàm writeFile() , bạn có thể tạo và chỉnh sửa file . Tiếp theo, bạn sẽ xóa các  file , một thao tác phổ biến khi bạn có các  file  tạm thời hoặc cần tạo dung lượng trên ổ cứng.
 Bước 3 - Xóa file  bằng unlink()
 Trong bước này, bạn sẽ xóa các file  bằng hàm unlink() trong module  fs . Bạn sẽ viết một tập lệnh Node.js để xóa file  groceries.csv mà bạn đã tạo trong phần trước.
Trong terminal của bạn, hãy tạo một file mới cho module Node.js này:
- nano deleteFile.js 
 Đến đây bạn  sẽ viết mã tạo một hàm deleteFile() không đồng bộ. Hàm đó sẽ chấp nhận một đường dẫn file  làm đối số, chuyển nó đến hàm unlink() để xóa nó khỏi hệ thống file  của bạn.
Trong editor của bạn, hãy viết mã sau:
const fs = require('fs').promises;  async function deleteFile(filePath) {   try {     await fs.unlink(filePath);     console.log(`Deleted ${filePath}`);   } catch (error) {     console.error(`Got an error trying to delete the file: ${error.message}`);   } }  deleteFile('groceries.csv'); Hàm unlink() chấp nhận một đối số: đường dẫn file  của file  bạn muốn xóa.
 Cảnh báo: Khi bạn xóa file  bằng hàm unlink() , file  sẽ không được gửi đến thùng rác hoặc thùng rác mà sẽ bị xóa vĩnh viễn khỏi hệ thống file  của bạn. Không thể hoàn tác hành động này, vì vậy hãy chắc chắn rằng bạn muốn xóa file  trước khi thực thi mã  của bạn .
 Thoát nano ,  đảm bảo  bạn lưu nội dung của file   bằng lệnh  CTRL+X
Bây giờ, thực hiện chương trình. Chạy lệnh sau trong terminal của bạn:
- node deleteFile.js 
Bạn sẽ nhận được kết quả sau:
OutputDeleted groceries.csv Để  xác nhận  file  không còn tồn tại, hãy sử dụng ls trong folder  hiện tại của bạn:
- ls 
Lệnh này sẽ hiển thị các file sau:
OutputdeleteFile.js   greetings.txt   readFile.js     writeFile.js  Đến đây bạn  đã  xác nhận  file  của bạn đã bị xóa bằng hàm unlink() .
Lúc này, bạn đã học cách đọc, ghi, chỉnh sửa và xóa file . Phần sau đây sử dụng một chức năng để di chuyển file vào các folder khác nhau. Sau khi học chức năng đó, bạn có thể thực hiện các việc quản lý file quan trọng nhất trong Node.js.
 Bước 4 - Di chuyển file  với rename()
 Các folder  được sử dụng để sắp xếp các file , vì vậy có thể lập trình di chuyển file  từ folder  này sang folder  khác giúp việc quản lý file  dễ dàng hơn. Bạn có thể di chuyển các file  trong Node.js bằng hàm rename() . Trong bước này, bạn sẽ di chuyển một bản sao của file  greetings.txt vào một folder  mới.
 Trước khi có thể viết mã module  Node.js  của bạn , bạn cần  cài đặt  một số thứ. Bắt đầu bằng cách tạo một folder  mà bạn sẽ chuyển file   của bạn  vào. Trong terminal  của bạn, hãy tạo một folder  test-data trong folder  hiện tại của bạn:
- mkdir test-data 
Bây giờ, hãy sao chép file  greetings.txt đã được sử dụng ở bước đầu tiên bằng lệnh cp :
- cp greetings.txt greetings-2.txt 
Hoàn tất cài đặt bằng cách mở file JavaScript để chứa mã của bạn:
- nano moveFile.js 
Trong module  Node.js của bạn, bạn sẽ tạo một hàm có tên là moveFile() gọi hàm rename() . Khi sử dụng hàm rename() , bạn cần cung cấp đường dẫn file  của file  root  và đường dẫn của vị trí đích. Đối với ví dụ này, bạn sẽ sử dụng hàm moveFile() để di chuyển file  greetings-2.txt vào folder  test-data . Bạn cũng sẽ đổi tên nó thành salutations.txt .
Nhập mã sau vào editor đang mở của bạn:
const fs = require('fs').promises;  async function moveFile(source, destination) {   try {     await fs.rename(source, destination);     console.log(`Moved file from ${source} to ${destination}`);   } catch (error) {     console.error(`Got an error trying to move the file: ${error.message}`);   } }  moveFile('greetings-2.txt', 'test-data/salutations.txt'); Như đã đề cập trước đó, hàm rename() nhận hai đối số: đường dẫn file  nguồn và đường dẫn file  đích. Chức năng này có thể di chuyển file  sang các folder  khác, đổi tên file  trong folder  hiện tại hoặc di chuyển và đổi tên cùng một lúc. Trong mã của bạn, bạn đang di chuyển và đổi tên file   của bạn .
 Lưu và thoát nano bằng cách nhấn CTRL+X
 Tiếp theo, thực hiện chương trình này với node . Nhập lệnh này để chạy chương trình:
- node moveFile.js 
Bạn sẽ nhận được kết quả này:
OutputMoved file from greetings-2.txt to test-data/salutations.txt Để  xác nhận  file  không còn tồn tại trong folder  hiện tại của bạn, bạn có thể sử dụng ls :
- ls 
Lệnh này sẽ hiển thị các file và folder này:
OutputdeleteFile.js   greetings.txt   moveFile.js     readFile.js     test-data       writeFile.js  Đến đây bạn  có thể sử dụng ls để liệt kê các file  trong folder  con test-data :
- ls test-data 
Tệp đã di chuyển của bạn sẽ xuất hiện trong kết quả :
Outputsalutations.txt  Đến đây bạn  đã sử dụng hàm rename() để di chuyển một file  từ folder  hiện tại của bạn vào một folder  con. Bạn cũng đã đổi tên file  bằng lệnh gọi hàm tương tự.
Kết luận
 Trong bài viết này, bạn đã học các chức năng khác nhau để quản lý file  với Node.js. Trước tiên, bạn đã tải nội dung của file  bằng readFile() . Sau đó, bạn đã tạo file  mới và nối dữ liệu vào file  hiện có bằng hàm writeFile() . Bạn đã xóa vĩnh viễn một file  bằng hàm unlink() , sau đó di chuyển và đổi tên file  bằng rename() .
 Làm việc với các file  theo chương trình là một chức năng quan trọng của Node.js. Các chương trình có thể cần xuất file  để  user  sử dụng hoặc có thể cần lưu trữ dữ liệu cho một ứng dụng không phải lúc nào cũng chạy. Với các chức năng của module  fs , các nhà phát triển có quyền kiểm soát cách file  được sử dụng trong các chương trình Node.js của  ta .
 Để tìm hiểu thêm về module  fs , bạn có thể đọc tài liệu Node.js. Nếu bạn muốn tiếp tục học Node.js, bạn có thể quay lại loạt bài Cách viết mã trong Node.js hoặc duyệt qua các dự án lập trình và  cài đặt  trên trang chủ đề Node của  ta .
Các tin liên quan
 

