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

第 5 課:檔案系統與路徑

fs/promises、fs.createReadStream/WriteStream。文件監視(fs.watch、chokidar)。路徑操作,__dirname,import.meta.url。臨時文件,原子寫入。全域模式。

💻 程式設計 — 第 5 課 第 5 課:檔案系統與路徑

Node.js 核心:從基礎到高級

第 2 部分:核心模組深入探討

亞洲開發網

1.fs/promise 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. 文件流

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. 路徑模組

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. 文件查看

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. 原子寫入

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. 全域模式(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'))

下一篇: 流和緩衝區 — 可讀、可寫、轉換、背壓。