Node.js操作文件

2023年 9月 23日 47.1k 0

Node.js操作文件

Node.js文件统计

每个文件都有一组细节,我们可以使用Node.js检查。特别是使用 fs 模块提供的 stat() 方法。

你调用它传递一个文件路径,一旦Node.js 得到文件的详细信息,它就会调用你传递的回调函数,有两个参数:一条错误消息,以及文件统计信息:

const fs = require('fs');

fs.stat('/Users/joe/test.txt', (err, stats) => {
  if (err) {
    console.error(err);
  }
  // we have access to the file stats in `stats`
});

Node.js还提供了一个sync方法,该方法会阻塞线程,直到文件状态准备就绪:

const fs = require('fs');

try {
  const stats = fs.statSync('/Users/joe/test.txt');
} catch (err) {
  console.error(err);
}

文件信息包含在stats变量中。使用统计数据我们可以提取哪些信息?

如果文件是目录或文件,则使用 stats.isFile()stats.isDirectory()

如果文件是使用 stats.isSymbolicLink() 的符号链接

使用 stats.size 显示文件大小(以字节为单位)。

还有其他的高级方法,但是你在日常编程中要用到的大部分是这个。

const fs = require('fs');

fs.stat('/Users/joe/test.txt', (err, stats) => {
  if (err) {
    console.error(err);
    return;
  }

  stats.isFile(); // true
  stats.isDirectory(); // false
  stats.isSymbolicLink(); // false
  stats.size; // 1024000 //= 1MB
});

如果你愿意,你也可以使用 fs/promises 模块提供的基于promisefsPromises.stat() 方法:

const fs = require('fs/promises');

async function example() {
  try {
    const stats = await fs.stat('/Users/joe/test.txt');
    stats.isFile(); // true
    stats.isDirectory(); // false
    stats.isSymbolicLink(); // false
    stats.size; // 1024000 //= 1MB
  } catch (err) {
    console.log(err);
  }
}
example();

您可以在官方文档中阅读更多关于 fs 模块的信息。

Node.js 文件路径

系统中的每个文件都有路径。在Linux和macOS上,路径可能如下所示: /users/joe/file.txt 而Windows计算机则不同,其结构如下: C:\users\joe\file.txt

在应用程序中使用路径时需要注意,因为必须考虑到这种差异。

您可以使用 const path = require('path'); 将此模块包含在文件中,然后开始使用它的方法。

从路径中获取信息

给定一个路径,您可以使用以下方法从中提取信息:

dirname :获取文件的父文件夹

basename :获取文件名部分

extname :获取文件扩展名

const notes = '/users/joe/notes.txt';

path.dirname(notes); // /users/joe
path.basename(notes); // notes.txt
path.extname(notes); // .txt

您可以通过为 basename 指定第二个参数来获取不带扩展名的文件名:

path.basename(notes, path.extname(notes)); // notes

使用路径

您可以使用 path.join() 连接路径的两个或多个部分:

const name = 'joe';
path.join('/', 'users', name, 'notes.txt'); // '/users/joe/notes.txt'

您可以使用 path.resolve() 获取相对路径的绝对路径计算:

path.resolve('joe.txt'); // '/Users/joe/joe.txt' if run from my home folder

在这种情况下,Node.js将简单地将 /joe.txt 追加到当前工作目录。如果指定第二个参数文件夹, resolve 将使用第一个作为第二个的基础:

path.resolve('tmp', 'joe.txt'); // '/Users/joe/tmp/joe.txt' if run from my home folder

如果第一个参数以斜杠开头,这意味着它是一个绝对路径:

path.resolve('/etc', 'joe.txt'); // '/etc/joe.txt'

path.normalize() 是另一个有用的函数,当它包含相对说明符(如 ... )或双斜杠时,它将尝试计算实际路径:

path.normalize('/users/joe/..//test.txt'); // '/users/test.txt'

resolve和normalize都不会检查路径是否存在。他们只是根据得到的信息计算出一条路径。

Node.js 中使用文件描述符

在能够与文件系统中的文件进行交互之前,必须获得文件描述符。

文件描述符是对打开的文件的引用,使用 fs 模块提供的 open() 方法打开文件时返回的数字(fd)。此编号( fd )唯一标识操作系统中打开的文件:

const fs = require('fs');

fs.open('/Users/joe/test.txt', 'r', (err, fd) => {
  // fd is our file descriptor
});

请注意,我们使用 r 作为 fs.open() 调用的第二个参数。

该标志意味着我们打开文件进行阅读。

您通常使用的其他标志包括:

标志 描述 如果文件不存在则创建文件
r+ 此标志打开文件读取 和写入
w+ 此标志打开文件读取 和写入 它还将流定位在开始 文件的
a 此标志打开文件写入 它还将流定位在结尾 文件的
a+ 此标志打开文件读取 和写入 它还将流定位在结尾 文件的

您也可以使用 fs.openSync 方法打开文件,该方法返回文件描述符,而不是在回调中提供它:

const fs = require('fs');

try {
  const fd = fs.openSync('/Users/joe/test.txt', 'r');
} catch (err) {
  console.error(err);
}

一旦你得到了文件描述符,无论你选择什么方式,你都可以执行所有需要它的操作,比如调用 fs.close() 和许多其他与文件系统交互的操作。

您也可以使用 fs/promises 模块提供的基于promisefsPromises.open 方法打开文件。

fs/promises 模块仅从Node.js v14开始可用。在v14之前,v10之后,您可以使用 require('fs').promises 。在v10之前,在v8之后,你可以使用 util.promisifyfs 方法转换为基于promise的方法。

const fs = require('fs/promises');
// Or const fs = require('fs').promises before v14.
async function example() {
  let filehandle;
  try {
    filehandle = await fs.open('/Users/joe/test.txt', 'r');
    console.log(filehandle.fd);
    console.log(await filehandle.readFile({ encoding: 'utf8' }));
  } finally {
    if (filehandle) await filehandle.close();
  }
}
example();

以下是 util.promisify 的示例:

const fs = require('fs');
const util = require('util');

async function example() {
  const open = util.promisify(fs.open);
  const fd = await open('/Users/joe/test.txt', 'r');
}
example();

要查看更多关于 fs/promises 模块的详细信息,请查看fs/promises API

Node.js 读取文件

Node.js中读取文件的最简单方法是使用 fs.readFile() 方法,向其传递文件路径、编码和回调函数,该函数将使用文件数据(和错误)调用:

const fs = require('fs');

fs.readFile('/Users/joe/test.txt', 'utf8', (err, data) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log(data);
});

或者,您可以使用同步版本 fs.readFileSync()

const fs = require('fs');

try {
  const data = fs.readFileSync('/Users/joe/test.txt', 'utf8');
  console.log(data);
} catch (err) {
  console.error(err);
}

您也可以使用 fs/promises 模块提供的基于promise的 fsPromises.readFile() 方法:

const fs = require('fs/promises');

async function example() {
  try {
    const data = await fs.readFile('/Users/joe/test.txt', { encoding: 'utf8' });
    console.log(data);
  } catch (err) {
    console.log(err);
  }
}
example();

fs.readFile()fs.readFileSync()fsPromises.readFile() 在返回数据之前读取内存中文件的全部内容。

这意味着大文件将对内存消耗和程序执行速度产生重大影响。

在这种情况下,更好的选择是使用流读取文件内容。

Node.js 写入文件

写入文件

Node.js中写入文件的最简单方法是使用 fs.writeFile() API。

const fs = require('fs');

const content = 'Some content!';

fs.writeFile('/Users/joe/test.txt', content, err => {
  if (err) {
    console.error(err);
  }
  // file written successfully
});

同步写入文件

或者,您可以使用同步版本 fs.writeFileSync()

const fs = require('fs');

const content = 'Some content!';

try {
  fs.writeFileSync('/Users/joe/test.txt', content);
  // file written successfully
} catch (err) {
  console.error(err);
}

您也可以使用 fs/promises 模块提供的基于promise的 fsPromises.writeFile() 方法:

const fs = require('fs/promises');

async function example() {
  try {
    const content = 'Some content!';
    await fs.writeFile('/Users/joe/test.txt', content);
  } catch (err) {
    console.log(err);
  }
}
example();

默认情况下,如果文件的内容已经存在,此API将替换该文件的内容。

可以通过指定标志来修改默认值:

fs.writeFile('/Users/joe/test.txt', content, { flag: 'a+' }, err => {});

您可能会使用的标志有

标志 描述 如果文件不存在则创建文件
r+ 此标志打开 reading 和 writing 的文件
w+ 此标志为 reading 和 writing 打开文件,并将流定位在文件的 beginning
a 此标志为 writing 打开文件,并将流定位在文件的 end
a+ 此标志为 reading 和 writing 打开文件,并将流定位在文件的 end

您可以在fs文档中找到有关标志的更多信息。

向文件追加内容

当您不想用新内容覆盖文件,而是想向文件中添加内容时,向文件追加内容非常方便。

例子

将内容附加到文件末尾的一个方便方法是 fs.appendFile() (及其对应的 fs.appendFileSync() ):

const fs = require('fs');

const content = 'Some content!';

fs.appendFile('file.log', content, err => {
  if (err) {
    console.error(err);
  }
  // done!
});

Promises例子

下面是一个 fsPromises.appendFile() 示例:

const fs = require('fs/promises');

async function example() {
  try {
    const content = 'Some content!';
    await fs.appendFile('/Users/joe/test.txt', content);
  } catch (err) {
    console.log(err);
  }
}
example();

Node.js 中使用文件夹

Node.js fs 核心模块提供了许多方便的方法来处理文件夹。

检查文件夹是否存在

使用 fs.access() (及其基于promise-based的 fsPromises.access() 对应项)检查文件夹是否存在,Node.js是否可以使用其权限访问它。

创建新文件夹

使用 fs.mkdir()fs.mkdirSync()fsPromises.mkdir() 创建新文件夹。

const fs = require('fs');

const folderName = '/Users/joe/test';

try {
  if (!fs.existsSync(folderName)) {
    fs.mkdirSync(folderName);
  }
} catch (err) {
  console.error(err);
}

读取目录的内容

使用 fs.readdir()fs.readdirSync()fsPromises.readdir() 读取目录的内容。

这段代码读取文件夹的内容,包括文件和子文件夹,并返回它们的相对路径:

const fs = require('fs');

const folderPath = '/Users/joe';

fs.readdirSync(folderPath);

你可以得到完整的路径:

fs.readdirSync(folderPath).map(fileName => {
  return path.join(folderPath, fileName);
});

您也可以过滤结果,只返回文件,并排除文件夹:

const isFile = fileName => {
  return fs.lstatSync(fileName).isFile();
};

fs.readdirSync(folderPath)
  .map(fileName => {
    return path.join(folderPath, fileName);
  })
  .filter(isFile);

重命名文件夹

使用 fs.rename()fs.renameSync()fsPromises.rename() 重命名文件夹。第一个参数是当前路径,第二个是新路径:

const fs = require('fs');

fs.rename('/Users/joe', '/Users/roger', err => {
  if (err) {
    console.error(err);
  }
  // done
});

fs.renameSync() 为同步版本:

const fs = require('fs');

try {
  fs.renameSync('/Users/joe', '/Users/roger');
} catch (err) {
  console.error(err);
}

fsPromises.rename() 是基于Promise的版本:

const fs = require('fs/promises');

async function example() {
  try {
    await fs.rename('/Users/joe', '/Users/roger');
  } catch (err) {
    console.log(err);
  }
}
example();

删除文件夹

使用 fs.rmdir()fs.rmdirSync()fsPromises.rmdir() 删除文件夹。

const fs = require('fs');

fs.rmdir(dir, err => {
  if (err) {
    throw err;
  }

  console.log(`${dir} is deleted!`);
});

要删除包含内容的文件夹,请使用 fs.rm() 和选项 { recursive: true } 以递归方式删除内容。

{ recursive: true, force: true } 使其在文件夹不存在时忽略异常。

const fs = require('fs');

fs.rm(dir, { recursive: true, force: true }, err => {
  if (err) {
    throw err;
  }

  console.log(`${dir} is deleted!`);
});

相关文章

服务器端口转发,带你了解服务器端口转发
服务器开放端口,服务器开放端口的步骤
产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
如何使用 WinGet 下载 Microsoft Store 应用
百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

发布评论