FS文件操作

写文件

写文件的意思感觉是写一个文件,准确来说,这里的写文件是把数据写入到一个文件中,当文件不存在时会创建一个文件。那么细化来看,过程应该是先打开一个文件,如果文件不存在就创建一个新的文件,然后把数据写入这个文件。

打开文件使用fs.open方法,写入数据使用fs.write方法,先做个例子。

var fs = require("fs");
fs.open("new.txt","w",function(err,fd){
    var buf = new Buffer("你好啊");
    fs.write(fd,buf,0,buf.length,0,function(err,written,buffer){});
})

首先打开文件new.txt,然后写入“你好啊”数据。说起来容易,同时发现这里有很多参数。下面将详细介绍open和write方法。

fs.open(path, flags, callback)

fs.openSync(path,flags) 是同步方法,return fd,如果有错误直接throw抛出错误。

path 参数,表示要打开文件的路径,flags标志参数,它限制打开的文件是可读、可写或可读写等方式,callback(err,fd)回调方法中fd表示打开文件的文件描述符。这里不好理解的是flags标志参数。

flags 参数可使用标志:

"r" 表示,打开文件进行读取。如果该文件不存在,将发生异常。

"r+" 表示,打开文件进行读取和写入。如果该文件不存在,将发生异常。

"rs" 与 "r" 一样,但采用同步方式,这个方式很消耗性能,一般情况下不会用到。

"rs+" 与 "r+" 一样,但采用同步方式,这个方式很消耗性能,一般情况下不会用到。

"w" 表示,打开文件进行写入。如果文件不存在会创建一个文件,这种写入方式会全部删除旧有的数据,然后再写入数据。

"w+" 表示,打开文件进行读取和写入。如果文件不存在会创建一个文件,这种写入方式会全部删除旧有的数据,然后再写入数据。

"wx" 和 "w" 相同,不同的是它是独占模式。

"wx+" 和 "w+" 相同,不同的是它是独占模式。

"a" 表示,打开文件进行追加,如果文件不存在会创建一个文件,这个模式不同于"w",它不会删除旧有的数据,而是会在后面追加数据。

"a+"  表示,打开文件进行追加和读取,如果文件不存在会创建一个文件,这个模式不同于"w",它不会删除旧有的数据,而是会在后面追加数据。

"ax" 和 "a" 相同,不同的是它是独占模式。

"ax+" 和 "ax" 相同,不同的是它是独占模式。

OK!看起来好多,还是做一些例子吧。

var fs = require("fs");
fs.open("new.txt","r",function(err,fd){
    var buf = new Buffer("你好啊");
    var c = fs.writeSync(fd,buf,0,buf.length,0);
    console.log(c)
})

上面的例子,只是把"w"改成"r",前提是new.txt文件存在,运行后,会出现错误提示,大概意思是无权写入。

Error: EPERM, operation not permitted

原因不言而喻,"r"表示只能被读,而不能写入。

下面这个例子用于说明"a"追加 和 "w"写入模式的差异,这个例子前提是,有一个已存在的new.txt文件,文件内有“你好啊”数据。

"w"模式

var fs = require("fs");
fs.open("new.txt","w",function(err,fd){
    var buf = new Buffer("1234");
    fs.writeSync(fd,buf,0,buf.length,0);
})

运行后,打开new.txt内容是“1234”而旧有的数据消失了。

我们在把new.txt文件内容改成“你好啊”,然后把"w"改成"a",运行!

var fs = require("fs");
fs.open("new.txt","a",function(err,fd){
    var buf = new Buffer("1234");
    fs.writeSync(fd,buf,0,buf.length,0);
})

运行后,打开文件new.txt文件,内容是“你好啊1234”。

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

fs.writeSync(fd, buffer, offset, length, position) 方法是同步写入,它返回写入多少bytes数量。

fd参数,文件描述符,通过fs.open得到。

buffer参数,是要写入的数据,Buffer对象,buffer尺寸的大小设置最好是8的倍数,效率较高。

yellowoffset参数,要写入buffer的起始位置。

length参数,要写入buffer的长度。通过offset和length规定buffer中那些数据应该被写入到文件。

position参数,写入到文件的什么位置。

callback((err, written, buffer)回调方法,当出现异常会抛出err,written是写入了多少bytes,buffer写入的数据。

fs.open 打开了文件,当然使用后应该关闭close文件,通过fs.close(fd, callback)和fs.closeSync(fd)方法可以关闭打开的文件,这个方法比较简单,不再多说。

上面写入方法是通过open得到fd(文件描述符)然后再写入文件的方式,其实还有其他方法。

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

fs.writeFileSync(filename, data, [options]) 同步方式。

filename String类型, 文件名称。

data String | Buffer类型,要写入的数据。

options[可选] Objectl 类型,默认值 {encoding:"utf8",flag:"w"}

callback(err) 回调函数

var fs = require("fs");
fs.writeFile("myfile.txt","Javascript很赞",function(err){
    if(!err)
    console.log("写入成功!")
})
fs.appendFile(filename, data, [options], callback)

fs.appendFileSync(filename, data, [options]) 同步方式。

参看 fs.writeFile 方法,差别就是 [options]的flag默认值是"a",所以它以追加方式写入数据。

读文件

有了前面的写文件,读文件就好办多了,还是老规矩,先写代码再做说明,但这次结合之前学到的,开发一个判断文件是否是png格式图片文件的程序。

假设当前目录下有个1.png文件,我们来判断这个文件是png图片。

var fs = require("fs");
fs.open("1.png","r",function(err,fd){
    // PNG头部 8 bytes是固定的,来判断文件前8bytes。
    var header = new Buffer([137,80,78,71,13,10,26,10]);
    var buf = new Buffer(8);
    fs.read(fd,buf,0,buf.length,0,function(err,bytesRead,buffer){
        if(header.toString() === buffer.toString()){
            console.log("是PNG格式图片文件");
        }
    })        
})

分析这个程序,先是用fs.open打开1.png文件,然后header数据是PNG图片标识数据,位于PNG图片前8个bytes,只要读取1.png文件前8bytes数据,然后对比一下数据是否一致就可以了。

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

fs.read(fd, buffer, offset, length, position) 方法是同步写入,它返回读取了多少bytes数量。

fd参数,文件描述符,通过fs.open得到。

buffer参数,是把读取的数据写入这个对象,是个Buffer对象。

offset参数,写入buffer的起始位置。

length参数,写入buffer的长度。

position参数,文件的什么位置开始读。

callback(err,bytesRead, buffer)回调方法,当出现异常会抛出err,bytesRead是读取了多少bytes,buffer读取到的数据。

和写文件同样的,除了fs.read方式读取文件外,还有一个读取文件的方式。

fs.readFile(filename, [options], callback)

fs.readFileSync(filename,[options]) 同步方式,retur读取到的数据。

filename String类型,表示要读取的文件名

options[可选] Object类型,默认值是 {encoding:null,flag:"r"}

callback(err,data) 回调函数,data表示读取的数据。

var fs = require("fs");
var data = fs.readFileSync("myfile.txt");
console.log(data.toString());
小结一下

读取和写入都有两种不同方式,一个是先open,然后操作读写,但需要手工调用fs.close关闭文件,这种方式适合于多次写入或读取。还有一次性服务的,writeFile/appendFile/readFile方法只是写入或读取一次,内部自动调用了fs.close方法。

上面两个小节内容稍微多了一点,以下几节内容相对轻松了,现在可以稍微休息一下。

截断文件

截断文件,说白了就是把整个文件内容删除了,然后再加入new Buffer(len)的空数据,这个方法多数情况没什么用。以下是方法。

fs.ftruncate(fd, len, callback)

fs.ftruncateSync(fd, len)

fs.truncate(path, len, callback)

fs.truncateSync(path, len)

这些方法很简单,做个例子说明一下。

var fs = require("fs");
fs.open("myfile.txt","w",function(err,fd){
    fs.ftruncate(fd,5,function(err){
        console.log(err)
    })
})
fs.truncateSync("myfile.txt",5);
文件链接

文件链接在“文件系统概述”中用官方口气介绍了一次。但通俗点更好理解,说白了就是为一个文件创建一个特殊的链接,这个链接看起来像是一个文件,和快捷方式很像,这样理解就可了,熟悉linux  ln命令的对文件链接会很熟悉这个概念。

还是先做实例,再说明。

var fs = require("fs");
fs.linkSync("file.txt","filelink.txt");
var fs = require("fs");
fs.link("file.txt","filelink.txt",function(err){
    console.log(err);
});

上面代码是为file.txt文件创建个“链接文件”filelink.txt,创建成功后,如果更改其中任何一个文件,相应的那个文件都会改变。

更改文件的查看和更新时间

这个很好理解,查看文件属性时,会看到文件的创建事件、更改时间、查看事件。看以下代码。

var fs = require("fs");
fs.utimes(
    "file.txt",
    new Date("1982-2-2"),
    new Date("1988-5-5"),
    function(err){}
);

上面代码的意思是,把file.txt文件的查看时间改成1982/2/2,最新更改时间改成1988/5/5。

fs.utimes(path, atime, mtime, callback)

fs.utimesSync(path, atime, mtime) 同步方式

path:String  更改的文件名字路径。

atime:Date 查看时间。

mtime:Date 更改时间。

callback(err) 回调函数。

fs.futimes(fd, atime, mtime, callback)

fs.futimesSync(fd, atime, mtime)

和utimes方法一样,只不过第一个参数是 fd 文件描述符。

监听文件

参看:“文件夹操作”一节。

在“文件夹操作”一节介绍了一种监听方式,下面还有一种专门监听文件的方法。

fs.watchFile(filename, [options], listener)

这个方法添加文件更改监听器。

filename:String 要监听的文件名。

options[可选]:Object,默认值是{ persistent: true, interval: 5007 } , persistent表示是否持久运作,这个意思是,true的时候当前process进程不会退出,如果是false,就不会阻止当前进程退出,不过可以使用 setInterval 方法模拟 persistent:true 。 interval 表示监听间隔,以毫秒为单位。

listener(currentStat,previousStat),监听器,一旦文件有变化就会触发这个回调函数,currentStat是更改后当前的文件状态,previousStat表示更改前的状态,这两个参数是fs.Stats类型。(参看“文件夹操作”一节)。

fs.unwatchFile(filename, [listener])

这个方法是停止监听的意思。

filename 要停止监听的文件名。

listener[可选],表示要停止监听的监听器。如果不指定,那么将会停止全部监听文件的监听器。

var fs = require("fs");
var handle1 = function(event,filename){
    console.log("1")
}
var handle2 = function(event,filename){
    console.log("2")
}
fs.watchFile("file.txt",handle1);
fs.watchFile("file.txt",handle2);

setTimeout(function(){
     fs.unwatchFile("file.txt",handle1);
},20000)

这里有两个监听器 handle1和handle2,当更改file.txt内容时,终端会打印出1 2,当20秒之后,再次更改file.txt文件,会发现终端只打印出 2 ,因为handle1已经被撤销了。