Chuyển đến nội dung chính

Bài 5: File System & Path

fs/promises, fs.createReadStream/WriteStream. File watching (fs.watch, chokidar). Path manipulation, __dirname, import.meta.url. Temporary files, atomic writes. Glob patterns.

💻 Lập trình — Bài 5 Bài 5: File System & Path

Node.js Core: Từ Cơ bản đến Nâng cao

Phần 2: Core Modules Deep Dive

xdev.asia

1. fs/promises API

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

// Đọc file
const content = await readFile('config.json', 'utf8')
const config = JSON.parse(content)

// Ghi file
await writeFile('output.txt', 'Hello World', 'utf8')

// Tạo thư mục (recursive)
await mkdir('data/logs/2026', { recursive: true })

// Liệt kê directory
const entries = await readdir('src', { withFileTypes: true, recursive: true })
const tsFiles = entries
  .filter(e => e.isFile() && e.name.endsWith('.ts'))
  .map(e => path.join(e.parentPath, e.name))

// File info
const info = await stat('package.json')
console.log(`Size: ${info.size}, Modified: ${info.mtime}`)

// Copy & rename
await cp('src', 'backup/src', { recursive: true })
await rename('old.txt', 'new.txt')

2. File Streams

import { createReadStream, createWriteStream } from 'node:fs'
import { pipeline } from 'node:stream/promises'
import { createGzip, createGunzip } from 'node:zlib'

// Copy file lớn bằng streams (không load hết vào memory)
await pipeline(
  createReadStream('large-file.csv'),
  createWriteStream('copy.csv')
)

// Nén file
await pipeline(
  createReadStream('data.json'),
  createGzip(),
  createWriteStream('data.json.gz')
)

// Giải nén
await pipeline(
  createReadStream('data.json.gz'),
  createGunzip(),
  createWriteStream('data.json')
)

3. Path Module

import path from 'node:path'

// ESM — lấy __dirname
const __dirname = import.meta.dirname  // Node.js 21+

path.join(__dirname, 'data', 'config.json')   // /app/data/config.json
path.resolve('..', 'shared')                  // Absolute path
path.basename('/app/src/index.ts')             // index.ts
path.extname('image.png')                      // .png
path.dirname('/app/src/index.ts')              // /app/src
path.parse('/app/src/index.ts')
// { root: '/', dir: '/app/src', base: 'index.ts', ext: '.ts', name: 'index' }

4. File Watching

import { watch } from 'node:fs/promises'

// Native fs.watch (recursive trên macOS/Windows)
const watcher = watch('src', { recursive: true })

for await (const event of watcher) {
  console.log(`${event.eventType}: ${event.filename}`)
}

5. Atomic Write

import { writeFile, rename } from 'node:fs/promises'
import { randomUUID } from 'node:crypto'

// Ghi atomic — tránh corrupt nếu crash giữa chừng
async function atomicWrite(filePath: string, data: string) {
  const tmpPath = `${filePath}.${randomUUID()}.tmp`
  await writeFile(tmpPath, data, 'utf8')
  await rename(tmpPath, filePath) // rename là atomic trên cùng filesystem
}

6. Glob Patterns (Node.js 22+)

import { glob } from 'node:fs/promises'

// Tìm tất cả .ts files
for await (const entry of glob('src/**/*.ts')) {
  console.log(entry)
}

// Collect thành array
const files = await Array.fromAsync(glob('**/*.md'))

Bài tiếp theo: Streams & Buffers — Readable, Writable, Transform, backpressure.