Ngữ cảnhCó thể bạn đang trong quá trình xử lý một thư mục hoặc chạy script build thì tiến trình đột ngột dừng lại. Terminal hiển thị một thông báo ngắn gọn: Error: EISDIR: illegal operation on a directory, read. Điều này xảy ra vì mã nguồn của bạn đang cố gắng mở một thư mục và đọc nội dung của nó như thể đó là một tệp tin đơn lẻ.
Tôi thường thấy lỗi này khi lập trình viên lặp qua một thư mục chứa các thư mục con, hoặc khi một biến cấu hình trỏ đến /uploads/ thay vì /uploads/image.png. Node.js mong đợi một tệp tin, nhưng nó lại tìm thấy một thư mục.
Tại sao lỗi này xảy raEISDIR viết tắt của "Error, Is Directory" (Lỗi, là thư mục). Ở cấp độ hệ thống, việc đọc một thư mục yêu cầu các quyền và phương thức khác với việc đọc một tệp tin. Các hàm như fs.readFile() hoặc fs.createReadStream() yêu cầu một bộ mô tả tệp (file descriptor). Nếu bạn truyền vào đường dẫn của một thư mục, hệ điều hành sẽ từ chối yêu cầu. Bạn đơn giản là không thể đọc dữ liệu nhị phân thô của một thư mục theo cùng cách bạn đọc tệp .txt hoặc .json.
Quy trình DebugBước đầu tiên là xác định chính xác đường dẫn gây ra lỗi crash. Nếu stack trace của bạn không rõ ràng, hãy thêm một dòng log ngay trước thao tác bị lỗi để xem biến đó thực sự chứa gì.
const filePath = path.join(__dirname, 'data', fileName);
console.log('Đang thử đọc đường dẫn:', filePath);
const data = fs.readFileSync(filePath);
Kiểm tra đầu ra cẩn thận. Bạn có thể thấy rằng fileName bị undefined, hoặc đường dẫn kết thúc đột ngột tại tên thư mục. Nếu lỗi bắt nguồn từ các công cụ như Webpack hoặc Vite, hãy kiểm tra các entry point của bạn. Một sai lầm phổ biến là trỏ source map hoặc asset include vào một thư mục thay vì một tệp tin cụ thể.
Giải pháp 1: Sử dụng withFileTypes để lọc tốt hơnKhi lặp qua một thư mục có hàng tá mục, đừng giả định mọi mục đều là tệp tin. Cách hiệu quả nhất để xử lý việc này trong Node.js hiện đại là sử dụng tùy chọn withFileTypes trong fs.readdirSync. Điều này cho phép bạn kiểm tra loại tệp mà không cần thực hiện thêm các lệnh gọi hệ thống cho từng mục riêng lẻ.
const fs = require('fs');
const path = require('path');
const dirPath = './data';
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
entries.forEach(entry => {
const fullPath = path.join(dirPath, entry.name);
if (entry.isDirectory()) {
console.log(`Đang bỏ qua thư mục: ${entry.name}`);
return;
}
const content = fs.readFileSync(fullPath, 'utf8');
console.log(`Đã đọc thành công: ${entry.name}`);
});
Giải pháp 2: Tinh chỉnh Glob Patterns của bạnNếu Gulp hoặc một công cụ build tương tự gây ra lỗi này, glob pattern của bạn có thể quá rộng. Ví dụ, gulp.src('src/assets/*') yêu cầu công cụ lấy mọi thứ trong thư mục đó, bao gồm cả các thư mục con. Gulp sau đó cố gắng đọc các thư mục con đó như các tệp tin, dẫn đến lỗi EISDIR.
Để khắc phục, hãy chỉ định cụ thể các phần mở rộng tệp tin:
// Gây lỗi: lấy cả thư mục
gulp.src('src/assets/*')
// An toàn: chỉ lấy các loại tệp cụ thể
gulp.src('src/assets/**/*.{png,jpg,svg}')
Giải pháp 3: Khắc phục sự cố đường dẫn MulterTrong các ứng dụng Express.js, lỗi này thường xuất hiện khi xử lý tải tệp lên. Multer cung cấp hai thuộc tính chính: destination (thư mục) và path (tệp cụ thể). Nếu bạn cố gắng đọc destination, ứng dụng sẽ bị crash.
// Điều này sẽ gây ra lỗi EISDIR
fs.readFile(req.file.destination, (err, data) => { ... });
// Đây là cách đúng
fs.readFile(req.file.path, (err, data) => { ... });
Xác minhBạn muốn xác nhận một đường dẫn cụ thể có phải là nguyên nhân không? Hãy chạy dòng lệnh nhanh này trong terminal của bạn:
node -e "require('fs').readFileSync('./your-suspect-path')"
Nếu nó trả về lỗi EISDIR, bạn đã xác nhận được đường dẫn đó là một thư mục. Khi bạn áp dụng bộ lọc hoặc sửa chuỗi đường dẫn, lệnh này sẽ trả về buffer của tệp hoặc mã nguồn của bạn sẽ bỏ qua nó hoàn toàn.

