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
fs
và 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ápasync/await
hoặ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