在NodeJS中操作文件常见的API

框架

浏览数:319

2019-8-17

一:如何读整个文件内容?

注意:读取文件和写入文件可能理解很枯燥,但是我每次学习这样的文章的时候都是为了下一篇文章做好准备的,因为我下一篇文章的demo需要使用到该方面的知识,所以我就会把需要的理解的知识统统记录一遍的。

在Node.js中,使用fs模块来实现所有文件及目录的创建,写入及删除操作。

1. 读文件的方法:
在执行读文件操作时,可以使用readFile方法与readFileSync方法读取文件,有Sync等字样的是同步方法,没有这个字样的是异步方法读取,同步方法和异步方法的区别是:同步方法立即返回操作的结果,先看下相关的API:

1)readFileSync同步读取文件API
使用方法读取如下:

fs.readFileSync(filename, [options]);

filename参数:用于指定读取文件的完整文件路径及文件名。
options参数:该值为一个对象,它可以指定读取文件时使用flag属性指定该文件采取什么操作,默认为 ‘r’; 可以指定值有如下:
‘r’: 读取文件,如果文件不存在会抛出异常。
‘r+’: 读取并写入文件,如果文件不存在会抛出异常。
‘rs’: 同步方式读取文件并且通知操作系统忽略本地文件系统的缓存,如果文件不存在会抛出异常。
‘w’: 写入文件,如果文件不存在则创建该文件,如果文件已存在则清空文件内容。
‘w+’: 读取并写入文件,其他功能和 ‘w’一样。
‘a’: 追加写入文件,如果文件不存在则创建该文件。
‘a+’: 读取并追加写入文件,文件不存在就创建文件。

在options参数中,我们可以使用 encoding属性指定使用何种编码格式来读取该文件,属性值有 ‘utf-8’, ‘ascii’, ‘base64’, 下面先看看简单的demo。如下所示:

先看下目录结构如下:

### 目录结构如下:
demo1                                       # 工程名
|   |--- readFile                           # 读取文件的文件夹            
|   | |-- index.html                        # html文件
|   | |-- index.js                          # js文件
|   | |-- package.json          
|   | |-- node_modules

如下代码读取文件代码:

const fs = require('fs');
try {
  const data = fs.readFileSync('./index.html', 'utf-8');
  // 等待操作结果返回,然后打印结果
  console.log(data);
} catch(e) {
  console.log('读取文件发生错误');
}

在命令行中执行 node index.js 然后打印结果如下:

2) 异步读取文件的API使用方法如下:
fs.readFile(filename, [options], callback);

filename 和 options 和 同步方法的参数是一样的。
callback参数 是用于文件读取完后执行的回调函数。如下代码所示:

const fs = require('fs');
fs.readFile('./index.html', 'utf-8', (err, data) => {
  if (err) {
    console.log('读取文件时发生错误');
  } else {
    console.log(data);
  }
});

执行的结果和上面是一样的。这里就不截图了。

二:如何写入整个文件内容?

写入文件,我们使用fs模块中的 writeFile 方法 或 wirteFileSync方法。writeFile使用方法如下(wirteFileSync方法类似,无非没有callback参数):

fs.writeFile(filename, data, [options], callback);

filename参数 为指定需要被写入文件的完整路径及文件名。

data参数 为指定需要写入的内容,值可以是一个字符串或一个Buffer对象,该字符串或缓冲区中的内容将被完整地写入到文件中。

options值为一个对象(可选),选项名为flag,它有如下选项值:

‘flag’: 用于指定该文件采取何种操作,默认值为 ‘w’, 含义是写入文件。该指定项所有值和上面readFile的值是一样的。
(文件不存在就创建该文件,文件存在时重写该文件)。

‘mode’: 该属性用于指定当文件被打开时对该文件的读写权限。默认值为 0666(可读写)。还有很多值自己可以百度了解下。

‘encoding’: 用于指定使用何种编码格式来写入该文件。可指定属性值为 ‘utf8’、’ascii’、’base64’。

callback: 该参数用于文件读取完毕时执行的回调函数。

下面我们简单的做一个demo,在我们目录下的 index.js 文件中编写代码,在该目录下创建一个 message.txt文件并写入两行文字。如下代码:

const fs = require('fs');
const str = '这是第一行。\r\n这是第二行';
fs.writeFile('./message.txt', str, (err) => {
  if (err) {
    console.log('写入文件操作失败');
  } else {
    console.log('写入文件操作成功');
  }
});

如下图执行命令:

在目录下会生成 message.txt文件,如下图

然后我们打开文件,会看到其写入的内容。

2)写入buffer对象,如下代码:

const fs = require('fs');
const str = new Buffer('我喜爱编程');
fs.writeFile('./message.txt', str, (err) => {
  if (err) {
    console.log('写入文件操作失败');
  } else {
    console.log('写入文件操作成功');
  }
});

在message.txt中可以看到 ‘我喜爱编程’ 几个字。

3)设置options参数flag属性选项,比如追加数据这些,如下代码:

const fs = require('fs');
const options = {
  flag: 'a'
};
fs.writeFile('./message.txt', '这是追加的数据', options, (err) => {
  if (err) {
    console.log('写入文件操作失败');
  } else {
    console.log('写入文件操作成功');
  }
});

message.txt内容编程如下了:我喜爱编程这是追加的数据

4)复制图片文件
我们可以通过readFile方法读取应用程序对应目录下的一个图片文件,在读取文件时使用base64编码,在该回调函数中使用writeFile方法,在该方法中使用base64编码将读取到的图片文件数据复制到另一个图片文件中。如下代码:

const fs = require('fs');

fs.readFile('./images/1.png', 'base64', (err, data) => {
  fs.writeFile('./images/xx.png', data.toString(), 'base64', (err) => {
    if (err) {
      console.log('写文件操作失败');
    } else {
      console.log('写文件操作成功');
    }
  });
});

在image下有一个 1.png, 它会先复制,然后写入 xx.png中(该文件之前不存在的,会创建该图片文件)。

三:如何在文件中的指定位置处读入内容?

3.1)打开文件open方法或openSync方法

要实现在文件中的指定位置处读入内容,首先我们需要打开该文件,fs模块中的open方法或openSync方法打开文件。open方法使用方式如下所示:

fs.open(filename, flags, [mode], callback);

前三个参数和readFile的参数是一个意思的。最后一个参数是执行完成后的回调函数。该回调函数有两个参数,第一个是打开文件失败时的错误对象,第二个参数为一个整数值,代表打开文件时返回的文件描述符。

下面我们来打开我们刚刚创建的 message.txt文件,如下代码:

const fs = require('fs');

fs.open('./message.txt', 'r', (err, fd) => {
  console.log(fd);
});

执行结果如下所示:

3.2)从指定的位置读取文件

如上面打开文件之后,我们可以在其回调函数使用fs模块中的read方法或readSync方法从文件的指定位置处读取文件,也可以使用fs模块中的write方法或writeSync方法从文件中指定处写入数据。

fs.read(fd, buffer, offset, length, position, callback);

fd参数是 上面open打开文件返回的文件描述符。
buffer参数 是一个buffer对象,用于指定将文件数据读取到那个缓存区中。
offset:用于指定向缓冲区中写入数据的开始位置。
length:用于指定从文件中读取的字节数。
position: 用于指定读取文件时的开始位置。
callback:用于指定文件操作完毕时的回调函数。如下所示:

function(err, bytesRead, buffer) {}

err: 为操作失败时的错误对象。
bytesRead: 代表实际读取的字节数。
buffer:为被读取的缓冲区对象。

下面我们来看个demo代码如下:

const fs = require('fs');
// message.txt 内容为:我喜爱编程这是追加的数据
fs.open('./message.txt', 'r', (err, fd) => {
  const buf = new Buffer(255);
  // 一个汉字的utf编码为三个字节数据
  fs.read(fd, buf, 0, 9, 3, (err, bytesRead, buffer) => {
    console.log(buffer.slice(0, bytesRead).toString()); // 喜爱编
  });
});

如上代码message.txt内容为:我喜爱编程这是追加的数据,position为3,从第三个字节开始读取文件,然后长度为9个字节,一个汉字3个字节,因此结果为 ‘喜爱编’;

四:如何在文件中的指定位置处写入内容?

在文件被打开后,可以使用fs模块中的write方法或writeSync方法从一个缓存区中读取数据并从文件的指定位置处写入这些数据。使用方法如下所示:

fs.write(fd, buffer, offset, length, position, callback);

fd参数为描述符。
buffer参数为一个Buffer对象,用于指定从哪个缓存区中读取数据。
offset参数用于指定从缓存区中读取数据时的开始读取位置。
length参数用于指定从缓存区中读取的字节数。
position参数值用于指定写入文件时的开始位置。
callback参数用于指定文件写入操作执行完毕时的回调函数。该回调函数如下:

function(err, written, buffer) {}

err参数为写入失败时的错误对象。
written: 代表被写入的字节数。
buffer: 代表被读取的缓冲区对象。

下面是一个简单的demo,如下所示:

const fs = require('fs');

const buf = new Buffer('我喜爱编程');

fs.open('./message.txt', 'w', (err, fd) => {
  fs.write(fd, buf, 3, 9, 0, (err, written, buffer) => {
    if (err) {
      console.log('写文件操作失败');
    } else {
      console.log('写文件操作成功');
    }
  });
}); 

在message.txt中显示为 喜爱编 这三个字。

五:如何创建与读取目录?

5.1) 创建目录mkdir和mkdirSync方法
在fs模块中,可以使用mkdir方法创建目录,该方法使用方式如下所示:

fs.mkdir(path, [mode], callback);

path参数用于指定需要被创建的目录完整路径及目录名。
mode参数用于指定该目录的权限,默认值为0777(表示任何人可读写该目录)。
callback是回调函数。
下面是一个简单的demo,如下所示:

const fs = require('fs');

fs.mkdir('./test', (err) => {
  if (err) {
    console.log('创建目录操作失败');
  } else {
    console.log('创建目录操作成功');
  }
});

如下所示:

5.2)读取目录readdir和readdirSync方法
在fs模块中,使用readdir方法读取目录,该方法使用如下所示:
fs.readdir(path, callback);

path参数用于指定需要被读取的目录的完整路径及目录名。
callback参数用于指定读取目录操作的回调函数。该回调函数如下所示:

function(err, file) {}

err 为读取目录操作失败的回调函数。
file参数值为一个数组,读取到的文件中的所有文件名。

如下demo所示:

const fs = require('fs');

fs.readdir('./', (err, files) => {
  if (err) {
    console.log('读取目录操作失败');
  } else {
    console.log(files);
  }
});

如下图所示:

六:如何查看与修改文件或目录的信息?

6.1)查看文件或目录的信息

在fs模块中,可以使用stat方法或lstat方法查看一个文件或目录的信息。这两个方法唯一的区别是当查看符号链接文件的信息
时,必须使用lstat方法。使用方法如下所示:

fs.stat(path, callback);
fs.lstat(path, callback);

path参数用于被查看的文件或目录的完整路径及文件名或目录名。
callback是回调函数。如下回调函数
function(err, stats) {}
err 参数值为查看文件或目录信息操作失败时触发的错误对象。
stats参数值为一个 fs.Stats对象,该对象有如下一些方法,在这些方法中不包含任何参数。

isFile: 用于判断被查看的对象是否为一个文件,如果是则返回true,否则的话返回false。
isDirectory: 用于判断被查看的对象是否为一个目录,如果是的话返回true,否则的话返回false。

还有很多很多其他的方法,这里不一一介绍,用的比较少,有需要的话,可以自己百度一下看看。

下面是使用 stat的使用demo,查看应用程序根目录下的 message.txt文件并且在回调函数中的第二个参数值 fs.Stats对象在控制台中的输出有哪些?

const fs = require('fs');

fs.stat('./message.txt', (err, stats) => {
  console.log(stats);
});

如下图所示显示:

6.2)检查文件或目录是否存在exists和existsSync方法

在fs模块中,可以使用exists方法检查一个文件或目录是否存在,该方法使用方式如下所示:

fs.exists(path, callback);

path参数:用于指定需要被检查的文件或目录的完整路径。
callback: 是回调函数,该回调函数如下所示:

function(exists) {}

exists参数,当文件或目录存在时,该参数值为true,否则的话,该参数值为false。

下面是一个简单的demo,如下代码所示:

const fs = require('fs');

// 该目录是存在的
fs.exists('./message.txt', (exists) => {
  console.log(exists); // true
});

// 该目录是不存在的
fs.exists('./message2.txt', (exists) => {
  console.log(exists); // false
});

6.3) 获取文件或目录的绝对路径realpath和realpathSync方法

在fs模块中,可以使用 realpath方法获取一个文件或目录的绝对路径,该方法使用如下所示:

fs.realpath(path, [cache], callback);

cache 参数是可选的,path和callback是必须的。
path参数为需要查看的文件或目录的完整路径。
cache参数为一个对象,其中存放了一些预先指定的路径。具体的百度下,这个参数用的不多。
callback是回调函数,该回调函数有2个参数,err参数值为获取目录的绝对路径失败的错误对象。resolvedPath参数值为获取
到的文件或目录的绝对路径。

下面是一个简单的demo,如下所示:

const fs = require('fs');

fs.realpath('./message.txt', (err, resolvedPath) => {
  if (err) {
    throw err;
  } else {
    console.log(resolvedPath);
  }
});

执行如下所示:

6.4) 使用ReadStream对象读取文件

在fs模块中,可以使用createReadStream方法创建一个将文件内容读取为流数据的ReadStream对象,该方法使用如下所示:

fs.createReadStream(path, [options]);

path 该参数用于指定需要被读取的文件的完整路径及文件名。
options为一个对象,它有如下属性:

flags: 用于指定对该文件采取什么操作,默认值为 ‘r’, 它的用法和readFile方法中的flags属性一样的。
encoding: 指定使用什么编码来读取该文件,可指定的值有 ‘utf8’, ‘ascii’, ‘base64’. 默认值为null.
start: 指定文件的开始读取位置。
end: 指定文件的结束读取位置。

还有很多其他的参数,这里不一一讲解,可以自行百度下即可。

下面简单的使用一个demo来了解下使用:如下代码:

const fs = require('fs');
/*
 一个汉字三个字节,message.txt的内容为:我喜爱编写代码
 因此从第三个位置开始,到第十二个位置结束,因此数据应该为 喜爱编写
*/
const options = {
  start: 3, 
  end: 12
};
const file = fs.createReadStream('./message.txt', options);

file.on('open', (fd) => {
  console.log('开始读取文件');
});

file.on('data', (data) => {
  console.log('读取到的数据:' + data);
});

file.on('end', () => {
  console.log('文件已全部读取完毕');
});

file.on('close', () => {
  console.log('文件被关闭');
});

file.on('error', (err) => {
  console.log('读取文件失败');
});

如下图所示:

我们可以使用 ReadStream对象的pause方法暂停data事件的触发,同时也意味着停止文件的读取操作。而已经被读取到的操作系统缓存区中的数据也将被暂时保存在操作系统缓冲区中,在使用了pause方法暂停data事件的触发之后,也可以使用ReadStream对象的resume方法恢复data事件的触发,也就意味着可以继续读取文件的数据。

如下demo:

const fs = require('fs');

const readStream = fs.createReadStream('./message.txt');

readStream.pause();

readStream.on('data', (data) => {
  console.log('获取到的数据为:' +data);
});

setTimeout(() => {
  readStream.resume();
}, 1000);

读取过程中,断听了一秒后,继续把数据读出来了。

注意:写入文件的方法是 WriteStream, 使用方式和读方式类似,这里不多介绍。

作者:龙恩0707