Node.js文件基本操作

Node.js文件基本操作

关于Node.js的文件操作,首先我们从利用Node.js实现文件拷贝的例子说起:

1
2
3
4
5
var fs = require('fs');
function copyFile(src, dist){
fs.writeFileSync(dist, fs.readFileSync(src));
}
copyFile('./test.txt','./testcopy.txt');

上述代码实现了,在当前的js同级目录下,复制text.txt文件内容到textcopy.txt文件中。对于小文件,我们可以这么实现拷贝。但当文件较大时,这样通过一次性读取文件内容到内存,再一次性写入磁盘,就有问题了。对于大文件的拷贝,我们通过下面的方式实现。

1
2
3
4
5
6
var fs = require('fs');
function copyFile(src, dist){
// fs.createWriteStream(dist).p(dist, fs.readFileSync(src));
fs.createReadStream(src).pipe(fs.createWriteStream(dist));
}
copyFile('./info.txt', './copyinfo.txt');

上述代码实现的是,边读边写,这样一点一点儿的实现大文件的拷贝。

Node.js的fs模块为我们操作文件提供了查询和操作函数。

查询文件统计信息

利用fs.stat方法查询文件或目录的元信息。

1
2
3
4
5
var fs = require('fs');
fs.stat('./info.txt', function(err, stats){
if(err) throw err;
console.log(stats);
})

控制台的输出为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{ dev: 16777218,
mode: 33188,
nlink: 1,
uid: 501,
gid: 20,
rdev: 0,
blksize: 4096,
ino: 11999814,
size: 3360,
blocks: 8,
atime: Sun Sep 18 2016 15:40:41 GMT+0800 (CST),
mtime: Sun Sep 18 2016 15:13:30 GMT+0800 (CST),
ctime: Sun Sep 18 2016 15:13:30 GMT+0800 (CST),
birthtime: Tue Sep 06 2016 18:38:47 GMT+0800 (CST) }

fs.stat()函数调用会将stats类的一个实例传递给回调函数,这个实例可调用一下方法:

1 stats.isFile():如果是标准文件,返回true
2 stats.isDirectory(): 如果是目录,返回true
3 stats.isBlockDevice(): 如果是块设备,返回true
4 stats.isCharacterDevice(): 如果是字符设备,返回true
5 stats.isSymbolicLink(): 如果是符号链接,返回true
6 stats.isFifo(): 如果是FIFO,返回true
7 stats.isSocket(): 如果是UNIX套接字,返回true

(ps: 除了前两个,后面的都有些 懵逼.jpg,待后续再补充。)

打开文件

fs.open方法,用来打开文件,然后使用文件描述符调用回调函数。

1
2
3
4
var fs = require('fs');
fs.open('./test.txt', 'r', function(err, fd){
//处理操作
})

第一个参数为文件路径,第二个参数为标志位,文件以哪种模式打开(r, r+, w, w+, a, a+:加号的区别在于,读写操作是否都具备)。
1 r:打开文本文件进行读取,数据流的位置在文件的起始处
2 r+:打开文件进行读写,数据流的位置在文件起始处
3 w:如果文件存在,将其清空,如果不存在,就创建文件写入数据,数据流位置在文件起始处
4 w+:打开文件进行读写,如果文件不粗安在就创建它,如果存在,将文件清零,数据流的位置在文件起始处
5 a:打开文件写入数据,如果文件不存在就创建,如果存在就将文件清零,数据流的位置在文件的结尾处,此后的写操作将数据追加到文件后面
6 a+:打开文件进行读写,如果文件不存在就创建,如果存在就将文件清零,数据流的位置在文件的结尾处,此后的写操作将数据追加到文件后面

读取文件

1
2
3
4
5
6
7
8
9
10
11
12
var fs = require('fs');
fs.open('./app.js','r+', function(err, fd){
if(err) throw err;
var readBuffer = new Buffer(1024),
bufferOffset = 0,
bufferLength = readBuffer.length,
filePosition = 100;
fs.read(fd, readBuffer, bufferOffset, bufferLength, filePosition, function(err, readBytes){
if(err) throw err;
console.log('just read ' + readBytes + ' bytes')
})
})

一旦将缓冲区传递给fs.open()函数,缓冲区的控制权就转交给了read命令,只有在回调函数被调用之后,缓冲区的控制权才会返还给你。在此之前不应该对缓冲区进行读写或让其他函数调用该缓冲区,否则则可能会读取不完整的数据,更糟糕的情况可能会并发地往该缓冲区中写入数据。

写入数据

通过fs.write()函数传递一个包含数据的缓冲区,可以向一个已打开的文件中写入数据。

1
2
3
4
5
6
7
8
9
10
11
12
var fs = require('fs');
fs.open('./info.txt','a', function(err, fd){
if(err) throw err;
var writeBuffer = new Buffer('测试写入数据'),
bufferOffset = 0,
bufferLength = writeBuffer.length,
filePosition = null;
fs.write(fd, writeBuffer, bufferOffset, bufferLength, filePosition, function(err, writeBytes){
if(err) throw err;
console.log('write ' + writeBytes + ' bytes')
})
})

传递给缓冲区包含以下一些信息:
1 准备写入的缓冲区的数据
2 待写入数据在缓冲区的起始位置
3 待写入数据的长度
4 从文件中的什么位置开始写入数据
5 写入文件操作结束后被调用的回调函数

在上述例子中,项文件中写入数据的起始位置为null,标明写入操作将当前文件的游标处开始。由于是以追加模式打开文件的,因此此时文件的游标位于文件的结尾处。

关闭文件

在实际应用程序中,一旦打开某个文件,最后就必须关闭它。为此,必须跟踪那些已经打开的文件的描述符,在最后不再需要它们的时候,使用fs.close(fd[,callback])关闭它们。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var fs = require('fs');
fs.open('./info.txt','a', function(err, fd){
if(err) throw err;
function notifyErr(err){
fs.close(fd, function(){ console.log('关闭文档')});
}
var writeBuffer = new Buffer('测试写入数据'),
bufferOffset = 0,
bufferLength = writeBuffer.length,
filePosition = null;
fs.write(fd, writeBuffer, bufferOffset, bufferLength, filePosition, function(err, writeBytes){
if(err) return notifyErr(err);
fs.close(fd, function(){ console.log('读写完毕,关闭文档')});
console.log('write ' + writeBytes + ' bytes');
})
})