文件操作在我们的日常功能模块之中是十分的常见的内容,nodeJS也不例外的为我们提供了之一操作内容,当时在我们了解文件操作的之前我们先来了解一下链接。


   连接可以理解成为一个纸箱相关文件内容的地址,其主要分成两种,如下:

  1.符文连接内容:符文连接指向的文件其中的内容多半是指向另一个文件的链接,有点像是我们C语言中的指针的一个概念,指向的内容是指向另一处内容模块的指向,不知道C的朋友也可以用window中的快捷方式来理解这样只一个内容,桌面上面的快捷方式实际上其存储的是实际开启文件的位置。而我们打开相关的快捷方式的时候是需要获取这一文件链接的的。

  2.硬链接:硬链接和符文连接的本质不同就在于其指向的文件是有实际内容的,比如我当前的目录下面有一个文件内容testing.txt,这指向这一文件的链接就是一个硬链接。当然没一个文件期初是有一个硬链接。


  接下来我们来具体的看一看文件操作模块到底为我们带来一些什么样的便利操作:

  一个文件有其自己的状态,内容,权限等等,nodeJS之中为我们提供了很多针对文件这一系列数据的操作方法,让我们更好的把控和操作文件内容。

  #首先我们来说一说文件的状态内容。

    nodejs之中有专门的一个类内容用来描述我们的文件的具体的状态内容,那就是fs.Stats类,这一个类对象及时一个文件状态属性对象。其中具体的相关信息如下:

Stats {
  dev: 2114,  //硬件设备文件id
  ino: 48064969,  //节点编号
  mode: 33188,  //操作权限
  nlink: 1,  //硬链接数
  uid: 85,  //文件拥有者的id
  gid: 100,    //用户组id
  rdev: 0,    //设备ID
  size: 527,  //文件字节量大小
  blksize: 4096, //文件磁盘区块大小
  blocks: 8, //分配的512B大小区块数量
  atimeMs: 1318289051000.1,
  mtimeMs: 1318289051000.1,
  ctimeMs: 1318289051000.1,
  birthtimeMs: 1318289051000.1,
  atime: Mon, 10 Oct 2011 23:24:11 GMT, //上次访问时间
  mtime: Mon, 10 Oct 2011 23:24:11 GMT, //文件修改事件
  ctime: Mon, 10 Oct 2011 23:24:11 GMT,  //文件状态变化时间
  birthtime: Mon, 10 Oct 2011 23:24:11 GMT } //文件创建时间  

上面可见我们可以从这一对象中获取的内容,nodeJS中如何来获取这一对象内容呢:我们可以通过fs.stat,fs.fstat等方法。

我们下面来具体的说明一下这两个方法吧。

  -- fs.stat(path, callback):函数获取当前文件的状态并检测文件是否可以正确打开。两个参数path表示文件路径内容,callback为回调函数内容,我们在编写回调函数的时候要为其提供一个参数内容err,系统自动传递参数,当发生错误的情况下则有error对象内容传递,如果正常则直接传递空对象或是null/undefined,下面看一段代码:

fs.stat('../testing/test.txt', (err,stats) => {
    if(err){
        console.log(err.message);   
    }
    else {
        console.dir(stats);
    }
});

上面是对应的结果。

  -- fs.fstat(fd, callback):这一个函数的功能和上一个函数相同,只是这一函数内容的第一个参数内容不再是路径而是文件描述符,什么是描述符,我们通过nodeJS来打开文件内容的时候会返回一个特别的文件描述符内容,实际上它打印出来就是一个数字内容而已。下面来看一段代码内容。

fs.open('../testing/test.txt', 'r' ,(err, fd) => { //打开相关文件内容获取描述符
    fs.fstat(fd, (err, stats) => {
        if(err){
            console.log(err.message);
        }
        else {
            console.dir(stats);
        }
    });
});

获取结果与上一段代码获取的结果相同。 

  -- fs.lstat(path, callback):这一函数也是相关文件信息获取函数,其传递的参数与stat函数的内容是相同的,但是两个函数的功能差别就在于这一个函数在获取的path是指向符号链接文件的时候,会获取当前符号文件内容的stats信息,而stat方法会自动的去获取当前的符号文件指向的文件内容。 


 

  下面我们来看看fs之中文件内容的操作有哪些我们是可以使用的。

  首先我们可能会想到的是链接一下我们的文件试试看。

  -- fs.access(path [, mode], callback):测试文件的权限内容。

   #path:文件的路径内容。

   #mode:文件权限模式,默认是fs.constants.F_OK

   #callback:文件的回调函数内容。

  当我们检测的可访问性失败了,则会报错。否则正常。这属于一个检测性质的文件内容。但是nodeJS内容并不推荐这样做,我们在异步的检测文件内容之后,由于有一段时间的数据返回的空挡,我们的文件权限类型有可能发生变化,和我们所检测到的相关内容不相同,所以在做文件的其他的操作之前进行检测是不推荐的。我们可以直接使用open函数来进行文件的打开,它同时也是会进行相关的检测的。

 

  当我们需要打开以个文件的时候,我们可以通过nodeJS之中的open方法来实现我们的操作。(当没有这一文件的时候,open会依据传递内容创建一个相应的文件内容。)

  -- fs.open(path, flags [, mode], callback):这里重点说明一下flags参数内容,表示的是打开文件的模式,其中涵盖了用户对当前的额文荣的操作权限其具体的内容如下列表

'r' - 以读取模式打开文件。如果文件不存在则发生异常。

'r+' - 以读写模式打开文件。如果文件不存在则发生异常。

'rs+' - 以同步读写模式打开文件。命令操作系统绕过本地文件系统缓存。

这对 NFS 挂载模式下打开文件很有用,因为它可以让你跳过潜在的旧本地缓存。 它对 I/O 的性能有明显的影响,所以除非需要,否则不要使用此标志。

注意,这不会使 fs.open() 进入同步阻塞调用。 如果那是你想要的,则应该使用 fs.openSync()。

'w' - 以写入模式打开文件。文件会被创建(如果文件不存在)或截断(如果文件存在)。

'wx' - 类似 'w',但如果 path 存在,则失败。

'w+' - 以读写模式打开文件。文件会被创建(如果文件不存在)或截断(如果文件存在)。

'wx+' - 类似 'w+',但如果 path 存在,则失败。

'a' - 以追加模式打开文件。如果文件不存在,则会被创建。

'ax' - 类似于 'a',但如果 path 存在,则失败。

'a+' - 以读取和追加模式打开文件。如果文件不存在,则会被创建。

'ax+' - 类似于 'a+',但如果 path 存在,则失败。

上面所说的是flags之中传递的参数内容,下面我们在来说明一下mode内容的,mode表示的是文件权限和文件类型信息。这么一说有没有感觉flags和mode有些相像,其实可以这么理解,flags实际上使用户的操作模式,其给定的一种操作模式,比如读取模式,而当此次操作形式超出了读取模式的权限的时候将不会成功,而当我们设置mode内容的时候,实际上是直接设置了文件本身的相关信息。所以两者之间并不冲突。那么mode参数可以传递哪些值呢:

文件类型标志包括:

S_IFBLK:文件是一个特殊的块设备

S_IFDIR:文件是一个目录

S_IFCHR:文件是一个特殊的字符设备

S_IFIFO:文件是一个FIFO设备

S_IFREG:文件是一个普通文件(REG即使regular啦)

S_IFLNK:文件是一个符号链接

其他模式标志包括:

S_ISUID:文件设置了SUID位

S_ISGID:文件设置了SGID位

S_ISVTX:文件设置了sticky位

用于解释st_mode标志的掩码包括:

S_IFMT:文件类型

S_IRWXU:属主的读/写/执行权限,可以分成S_IXUSR, S_IRUSR, S_IWUSR

S_IRWXG:属组的读/写/执行权限,可以分成S_IXGRP, S_IRGRP, S_IWGRP

S_IRWXO:其他用户的读/写/执行权限,可以分为S_IXOTH, S_IROTH, S_IWOTH

还有一些用于帮助确定文件类型的宏定义,这些和上面的宏不一样,这些是带有参数的宏,类似与函数的使用方法:

S_ISBLK:测试是否是特殊的块设备文件

S_ISCHR:测试是否是特殊的字符设备文件

S_ISDIR:测试是否是目录(我估计find . -type d的源代码实现中就用到了这个宏)

S_ISFIFO:测试是否是FIFO设备

S_ISREG:测试是否是普通文件

S_ISLNK:测试是否是符号链接

S_ISSOCK:测试是否是socket

上面的一系列值我们称之为宏定义,当我们需要传值的情况下,我们需要传递的是多个宏定义的组合值,通俗的来说其实每一个宏定义是一个特殊的二进制内容变量。我们使用这些值与按位与(&)的形式来组合不同的内容。

之后我们来看一段代码:

fs.open('../testing/test.txt', 'r' ,(err, fd) => {
    if(err){
        console.log(err.message);
    }
    else {
        console.dir(fd);
    }
});
//结果为3

  

  当我们打开文件内容之后要对页面内容进行操作。

  文件读取内容内容。在文编呗打开之后我们获取了相关的文件描述符内容,之后我们就可以进行对这一针对性文件的操作内容。读取文件内容I/O操作从磁盘之中将我们需要的内容存放到缓存之中。下面我们来了解一下读取函数内容。

  -- fs.read(fd, buffer, offset, length, position, callback):读取文件中制定位置的内容到缓存对象之中。

   #fd:表示的是相关的文件的描述符内容。

   #buffer:是存放读取到的数据的Buffer对象。

   #offset:是Buffer之中开始写入的偏移量。

   #length:指定要读取的字节数。

   #position:指定从文件中开始读取的位置。

   #callback:回调函数内容其中有三个参数内容(err, bytesRead, buffer)

    err表示是否有错误,如果有的这传递相关的错误信息。

    bytesRead:读取的文件内容的长度。

    buffer:为最终获取的字符串内容。

让我们来看一段示例代码内容吧:

var buf = Buffer.alloc(10);
fs.open('../testing/test.txt', 'r', (err, fd) => {
    if(err){
        console.log(err.message);   
    }
    else {
        fs.read(fd, buf, 1, 9, 0, (err, bytesRead, buffer) => {
            if(err){
                console.log(err.message);   
            }
            else{
                console.dir(bytesRead);
                console.dir(buffer);
            }
            console.log(buf);
        });   
    }
});

我们可以从图中看到的,Buffer的内容是不相同的,但是如果我们调用toString()方法的话,我们可以看到,实际上两者展示出来的内容是相同的。这是应为返回来的内容第二个内容数据为10进制的,而之后展示出来的Buffer内容则为16进制的。

 

  当然读取方法不单单只有一个。

  -- fs.readFile(path [,option], callback):这一函数用于读取文件的全部内容,传递的参数内容内容如下:

   #path:文件路径或是文件描述符。

   #option:传递的选填参数内容,可以传递string也可以是对象内容。

    - encoding:编码格式内容。

    - flags:文件操作权限,默认为‘r’。

   #callback:回调函数内容其中有两个参数需要传递。

    - err:错误信息。

    - data:数据内容。

我们来看一段代码。

fs.readFile('../testing/test.txt', (err, data) => {
    if(err){
        console.log(err.message);
    } else {
        console.dir(data);  
        console.log(data.toString());
    }
});

其结果就是

  

  当文件被打开之后我们可能不仅仅需要读取,可能还需要对文件内容进行修改或者是写入操作等,这样我们要通过怎么样的方式来进行操作呢。

  -- write(fd, buffer [, position [, encoding]], callback):写入Buffer文件内容到fd标识符之中。

   #fd:表示的将要写入的文件描述符内容。

   #buffer:写入文件之中的相关的缓存内容。

   #position:文件录入内容起始位置Bufffer的起始位置。

   #encoding:文件编码格式。

   #callback:回掉函数内容

    - err:错误相关信息。

    - written:传递进入的参数内容长度(多少字节)。

    - string:写入的内容是什么。

下面看到一段代码:

fs.open('../testing/test.txt', 'r+', (err, fd) => {
    fs.write(fd, Buffer.from(' something'), (err, written, buffer) => {
        console.log(written);
        console.dir(buffer);
    });
});

 通过上面这一段代码内容我们可以为test.txt文件添加内容‘ semothing’并且内容是将原本内容进行个替换,而不是进行插入添加。但是替换的内容只是在与其输入的字符串长度等长度的部分内容。但是,当我们修改了open传递的flag信息的时候,当flags内容传递成为W或者是W+的情况之下我们在使用write函数的时候将会将整个文件内容替换掉。还有就是当我们在flags传递的内容是r的时候我们是不能进行写操作的。

 

  -- fs.writeFile(file, data [,options], callback):异步地写入数据到文件,如果文件已经存在,则替代文件。

   #file:可以是文件路径或者是文件描述符。

   #data:传递将要写入的文件内容。

   #options:可以传递一个字符串或者是一个对象内容。

    -encoding:文件编码格式。

    -mode:文件权限模式设置。

    -flag:文件操作权限。

   #callback:回掉函数内容传递尝试内容(err)。

我们来看一段代码

fs.writeFile('../testing/test.txt', 'there is a something', (err) => {});  //结果就是文件内容被替换成为传递的内容。

 

  当然我们也可以使用流来进行文件的操作。 创建可读流内容  

  -fs. createReadStream(path [,option]): 

   #path:文件内容路径。

   #option:非必填,可以是string或是对象。

    -flags:文件操作权限

    -encoding:path的编码格式

    -fd:文件描述符文件,如果传递了fd则默认不适用path,

    -mode:文件的操作模式

    -autoClose:当有错误或是结束了当前流的时候会依据此参数来确定当前的fd是否会自动的关闭。如果不关闭的话代码之中要注意自助关闭,否则可能会泄露

    -start:文件开始读取的偏移量。

    -end:文件结束的偏移量。

  我们来具体的看一段代码吧。

 

var readS = fs.createReadStream('../testing/test.txt', {flags:'r+'});
console.dir(readS);.//获取的相关结果是,一个阅读流。 

 具体的流内容的操作我们可以在流篇章看见。

  当然我们实际上也是可以创建一个可写流的。

  -- fs.createWriteStream(path [,option]):创建可写流内容其中的传递的内容实际和创建可读流的时候是相同的情况,所以当我们使用的也是需要注意的。

 

  我们同时也可以追加相关的文件内容

  -- fs.appendFile(file,data [,options], callback):一步的最佳数据到相关的文件内容,当我们的文件不存在的时候,则函数会自动的创建这一文件内容。

   #path:文件路径内容。

   #data:想要追加的数据内容,String, Buffer

   #options:可以是一个string或者是一个对象内容。

    -encoding:编码格式内容。

    -mode:文件的权限格式类型。

    -flag:用户对文件的操作权限。

   #callback:文件的回调函数内容。

上代码。

fs.appendFile('../testing/test.txt', ', check appendFile', (err) => {});

结果是,在文件的末尾添加了当前传递的data参数内容。

 

  我们有的时候需要对文件内容进行拷贝操作这个时候我们就可以通过copyFile,

  -- fs.copyFile(src, dest [,flags], callback):复制文件内容,到指定的路径文件下。

   #src:需要复制的文件路径内容。

   #dest:指定的文件路径内容。

   #flags:拷贝操作修饰符。

   #callback:回调函数。

我们来看一段代码。

fs.copyFile('../testing/test.txt', './test.txt', (err) => {});

 

  最后当我们操作完成之后我们需要关闭文件内容,这样一面我们缓存之中的内容被泄露。

  -- fs.close(fd, callback):文件关闭

   #fd:文件描述符。

   #callback:文件回调函数。

 

  当然我们有时需要对于文件夹进行操作。

  -- fs.mkdir(path [,mode], callback):创建一个文件路径。

   #path:创建文件夹的路径

   #mode:文件夹权限模式。

   #callback:回调函数内容

  -- fs.mkdtemp(prefix [,options], callback):创建一个唯一的临时目录

    #prefix:参数为创建临时文件的路径。创建临时时会自动生成一个唯一序列 

   #mode:文件夹的权限模式

   #callback:回调函数内容。

 

  当然我们也可以对于读取文件夹之中的内容。

  -- fs.readdir(path [,options] , callback): 读取文件夹内容。

   #path:为需要查询的文件夹内容。

   #callback:回调函数。其中有两个参数内容,err为错误信息,第二个参数为file为当前文件夹之名称不存在‘.’ '..'的文件名称所组成的数组。

代码示例

fs.readdir('../testing', (err,stats) => {console.dir(stats)});

结果类似如下


  文件内容操作之外,我们还可以针对文件权限或是状态内容进行相关的修改或是操作。

  -- fs.chomd(path, mode, callback):赋予当前path文件以mode之中的文件模式。

   #path:文件路径。

   #mode:文件权限。

   #callback:回调函数内容。

  文件权限内容可以看上文之中的mode介绍内容。

  -- fs.chown(path, uid, gid, callback):改变文件的所有组。

   #path:文件路径内容。

   #uid:用户ID。

   #gid:组别ID。

   #callback:回调函数。

  -- fs.fsync(fd,callback):同步当前的内容到文件

   #fd:文件描述符。

   #callback:文件内容

  -- fs.ftruncate(fd [,len], callback):文件截断到指定的长度。

   #fd:文件描述符。

   #len:文件长度。

   #callback:回调函数。

  -- fs.futimes(fd, atime, mtime, callback):改变文件的系统时间戳。

   #fd:文件描述符。

   #atime:文件链接时间。

   #mtime:文件修改时间。

   #callback:回调函数。

 

当然FS模块为我们提供的将不仅仅是上面这一些内容,当前只是比较基础的内容的学习。参照的文本包括官方文档和node权威指南内容。

 

  

  

 

posted on 2017-12-25 17:24  平川心  阅读(199)  评论(0编辑  收藏  举报