Skip to content
On this page

Node.js 文件系统操作

Node.js提供了丰富的文件系统操作API,允许开发者直接与操作系统文件系统进行交互。

文件系统模块(fs)

Node.js的fs模块提供了文件系统操作的API,支持同步和异步操作。

导入fs模块

javascript
const fs = require('fs');
const fsPromises = require('fs').promises;
const path = require('path');

异步文件操作

读取文件

javascript
// 异步读取文件
fs.readFile('./data.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('读取文件失败:', err);
    return;
  }
  console.log('文件内容:', data);
});

// 使用Promise方式
const { readFile } = require('fs').promises;

async function readTextFile(filePath) {
  try {
    const data = await readFile(filePath, 'utf8');
    console.log('文件内容:', data);
    return data;
  } catch (err) {
    console.error('读取文件失败:', err);
    throw err;
  }
}

写入文件

javascript
// 异步写入文件
fs.writeFile('./output.txt', 'Hello, Node.js!', (err) => {
  if (err) {
    console.error('写入文件失败:', err);
    return;
  }
  console.log('文件写入成功');
});

// 追加内容到文件
fs.appendFile('./log.txt', `${new Date().toISOString()} - 日志信息\n`, (err) => {
  if (err) {
    console.error('追加文件失败:', err);
    return;
  }
  console.log('日志追加成功');
});

// 使用Promise方式
const { writeFile, appendFile } = require('fs').promises;

async function writeFiles() {
  try {
    await writeFile('./output.txt', 'Hello, World!');
    await appendFile('./log.txt', '新日志条目\n');
    console.log('文件操作完成');
  } catch (err) {
    console.error('文件操作失败:', err);
  }
}

检查文件状态

javascript
// 检查文件是否存在和状态
fs.stat('./data.txt', (err, stats) => {
  if (err) {
    console.error('获取文件状态失败:', err);
    return;
  }
  
  console.log('文件信息:', {
    isFile: stats.isFile(),
    isDirectory: stats.isDirectory(),
    size: stats.size,
    birthTime: stats.birthtime,
    mtime: stats.mtime
  });
});

// 使用Promise方式
const { stat } = require('fs').promises;

async function checkFile(filePath) {
  try {
    const stats = await stat(filePath);
    if (stats.isFile()) {
      console.log(`${filePath} 是一个文件`);
    } else if (stats.isDirectory()) {
      console.log(`${filePath} 是一个目录`);
    }
    return stats;
  } catch (err) {
    if (err.code === 'ENOENT') {
      console.log(`${filePath} 不存在`);
    } else {
      console.error('检查文件失败:', err);
    }
    throw err;
  }
}

同步文件操作

javascript
try {
  // 同步读取文件
  const data = fs.readFileSync('./data.txt', 'utf8');
  console.log('文件内容:', data);
  
  // 同步写入文件
  fs.writeFileSync('./output.txt', '同步写入的内容');
  
  // 同步检查文件状态
  const stats = fs.statSync('./data.txt');
  console.log('文件大小:', stats.size);
} catch (err) {
  console.error('同步操作失败:', err);
}

目录操作

创建和删除目录

javascript
// 创建目录
fs.mkdir('./new-directory', { recursive: true }, (err) => {
  if (err) {
    console.error('创建目录失败:', err);
    return;
  }
  console.log('目录创建成功');
});

// 读取目录内容
fs.readdir('./data', (err, files) => {
  if (err) {
    console.error('读取目录失败:', err);
    return;
  }
  console.log('目录内容:', files);
});

// 删除目录
fs.rmdir('./temp-directory', (err) => {
  if (err) {
    console.error('删除目录失败:', err);
    return;
  }
  console.log('目录删除成功');
});

// 使用Promise方式
const { mkdir, readdir, rmdir, rm } = require('fs').promises;

async function directoryOperations() {
  try {
    // 递归创建目录
    await mkdir('./path/to/new/directory', { recursive: true });
    
    // 读取目录
    const files = await readdir('./data');
    console.log('目录文件:', files);
    
    // 删除目录(可以删除非空目录)
    await rm('./temp-directory', { recursive: true, force: true });
    
    console.log('目录操作完成');
  } catch (err) {
    console.error('目录操作失败:', err);
  }
}

流式文件操作

读取流

javascript
const fs = require('fs');

// 创建读取流
const readStream = fs.createReadStream('./large-file.txt');

readStream.on('data', (chunk) => {
  console.log(`接收到 ${chunk.length} 字节的数据`);
});

readStream.on('end', () => {
  console.log('文件读取完成');
});

readStream.on('error', (err) => {
  console.error('读取流错误:', err);
});

写入流

javascript
// 创建写入流
const writeStream = fs.createReadStream('./output.txt');

writeStream.write('第一行数据\n');
writeStream.write('第二行数据\n');
writeStream.end('最后一行数据\n');

writeStream.on('finish', () => {
  console.log('写入完成');
});

管道操作

javascript
// 文件复制 - 使用管道
const readStream = fs.createReadStream('./source.txt');
const writeStream = fs.createWriteStream('./destination.txt');

readStream.pipe(writeStream);

// 处理错误
readStream.on('error', (err) => {
  console.error('读取错误:', err);
});

writeStream.on('error', (err) => {
  console.error('写入错误:', err);
});

writeStream.on('finish', () => {
  console.log('复制完成');
});

高级文件操作

文件监听

javascript
// 监听文件变化
fs.watch('./config.json', (eventType, filename) => {
  if (filename) {
    console.log(`文件 ${filename} 发生了 ${eventType} 事件`);
  }
});

// 更详细的监听
fs.watch('./data', { recursive: true }, (eventType, filename) => {
  console.log(`事件类型: ${eventType}`);
  console.log(`文件名: ${filename}`);
});

文件权限操作

javascript
// 更改文件权限
fs.chmod('./script.sh', 0o755, (err) => {
  if (err) {
    console.error('更改权限失败:', err);
    return;
  }
  console.log('权限更改成功');
});

// 获取文件权限
fs.stat('./data.txt', (err, stats) => {
  if (err) {
    console.error('获取状态失败:', err);
    return;
  }
  console.log('文件权限:', stats.mode);
});

实用工具函数

javascript
const fs = require('fs').promises;
const path = require('path');

// 递归读取目录
async function readDirRecursive(dir) {
  const entries = await fs.readdir(dir, { withFileTypes: true });
  
  const files = [];
  for (const entry of entries) {
    const fullPath = path.join(dir, entry.name);
    
    if (entry.isDirectory()) {
      const nestedFiles = await readDirRecursive(fullPath);
      files.push(...nestedFiles);
    } else if (entry.isFile()) {
      files.push(fullPath);
    }
  }
  
  return files;
}

// 安全写入文件(创建目录如果不存在)
async function safeWriteFile(filePath, data) {
  const dir = path.dirname(filePath);
  
  // 确保目录存在
  await fs.mkdir(dir, { recursive: true });
  
  // 写入文件
  await fs.writeFile(filePath, data);
}

// 复制文件
async function copyFile(src, dest) {
  const readStream = require('fs').createReadStream(src);
  const writeStream = require('fs').createWriteStream(dest);
  
  return new Promise((resolve, reject) => {
    readStream.pipe(writeStream);
    writeStream.on('finish', resolve);
    writeStream.on('error', reject);
    readStream.on('error', reject);
  });
}

// 检查路径是否存在
async function pathExists(filePath) {
  try {
    await fs.access(filePath);
    return true;
  } catch {
    return false;
  }
}

文件编码处理

javascript
// 处理不同编码的文件
const fs = require('fs');

// 读取二进制文件
fs.readFile('./image.jpg', (err, data) => {
  if (err) throw err;
  console.log('文件大小:', data.length, '字节');
});

// 读取UTF-8编码文件
fs.readFile('./text-utf8.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log('UTF-8内容:', data);
});

// 读取Base64编码
fs.readFile('./file.txt', 'base64', (err, data) => {
  if (err) throw err;
  console.log('Base64编码:', data);
});

错误处理最佳实践

javascript
const fs = require('fs').promises;

async function robustFileOperation(filePath) {
  try {
    // 检查文件是否存在
    await fs.access(filePath);
    
    // 读取文件
    const data = await fs.readFile(filePath, 'utf8');
    return data;
  } catch (err) {
    switch (err.code) {
      case 'ENOENT':
        console.error('文件不存在:', filePath);
        break;
      case 'EACCES':
        console.error('没有权限访问文件:', filePath);
        break;
      case 'EISDIR':
        console.error('路径是一个目录,不是文件:', filePath);
        break;
      default:
        console.error('文件操作失败:', err);
    }
    throw err;
  }
}

Node.js的文件系统操作提供了强大而灵活的功能,可以满足各种文件处理需求。合理使用同步和异步操作,以及流式处理,可以构建高效、可靠的文件处理应用程序。