006 I/O模块fs

[a] fs文件系统

        在node中,与文件系统的交互时非常重要的,服务器的本质就是将本地的文件发送给远程的客户

        node通过fs模块实现与文件的交互

        fs是node中的核心模块(内部模块)

        fs系统最主要的操作就是文件的读取和写入

[B] 同步和异步

        1. fs中所有的操作都有两种形式:同步和异步;异步的版本中函数最后一个参数为回调函数,回调函数的第一个参数包含了错误信息(error)。

        2. 同步文件会阻塞程序的运行,也就是除非文件操作完毕,否则不会执行下面的程序

        3. 异步文件不会阻塞程序的运行,而是在操作完成时通过回调函数返回。

        4. 建议大家使用异步方法,比起同步,异步方法性能更高,速度更快,而且没有阻塞。

            菜鸟教程学习:https://www.runoob.com/nodejs/nodejs-tutorial.html

  异步文件:

    全部读取:readFile        全部写入:writeFile

    部分读取:read          部分写入:write

  同步文件:

    全部读取:readFileSync      全部写入:writeFileSync

    部分读取:readSync        部分写入:writeSync

  1. fs.read() 读取文件部分内容(根据参数而定)

    语法

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

    参数:

      fd - 通过 fs.open() 方法返回的文件描述符。

      buffer - 数据写入的缓冲区。

      offset - 缓冲区写入的写入偏移量。

      length - 要从文件中读取的字节数。

      position - 文件读取的起始位置,如果 position 的值为 null,则会从当前文件指针的位置读取。

      callback - 回调函数,有三个参数err, bytesRead, buffer, err 为错误信息, bytesRead 表示读取的字节数,buffer 为缓冲区对象。

    【注】:

      使用fs.read()方法读取文件内容时,首先需要一个文件描述符fd,fs.read()方法可以实现部分文件内容的读取。

      通过length和position参数可以指定读取文件内容的长度和读取内容的起始位置。

  2. fs.readFile() 读取文件全部内容

    语法:

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

    参数:

      filename —— 表示要读取的文件

      callback —— 回调函数有2个参数 (err, data),参数 data 是文件的内容。如果没有指定参数encoding, 则返回值为Buffer。

    【注】:

      fs.readFile()方法能且只能读取文件的全部内容,通过设置编码方式可以以字符串或Buffer的形式返回读结果。

  3. fs.read()和fs.readFile()方法的比较

    本质上讲,fs.readFile()方法是对fs.read()方法的进一步封装,fs.readFile()方法可以方便的读取文件的全部内容。

    相比fs.readFile()方法,使用fs.read()方法读取文件的全部内容可操作性要强很多。首先要用fs.stat判断文件的大小,然后使用fs.open()创建文件描述符,最后再使用fs.read()方法读取文件内容。

   
[C] 文件的写入

            // 导入fs模块

                var fs = require("fs");

        1.同步文件写入

            // 1. 打开文件
            var fd = fs.openSync("./Nodejs/filesystem/hello.txt", "w")

            // 2. 向文件中写入内容
            fs.writeSync(fd, "今天天气不错欸,我们去爬山吧~~~~", 5);

            // 3. 关闭文件
            fs.closeSync(fd);

        2. 异步文件写入

            // 1. 打开文件
            fs.open("./Nodejs/filesystem/hello.txt", "w", function(err, fd){
                if(err){
                    return console.log(err);
                }

                // 2. 向文件中写入内容
                fs.write(fd, "今天天气不错欸,我们去爬山吧~~~~", function(err){
                    if(!err){
                        console.log("文件写入成功!");
                    }
                });

                // 3. 关闭文件
                fs.close(fd,function(er){
                    if(!er){
                        console.log("文件成功关闭~~~");
                    }
                });
            })    
       
  3. 简单文件写入

            writeFile函数介绍:

                fs.writeFile(fd, data, [option,] callback)

                    第一个参数:fd,文件名或文件描述符(结合fs.open)

                    第二个参数:data, 要写入文件的数据,可以是 String(字符串) 或 Buffer(缓冲) 对象

                    第三个参数:默认为:{encoding, mode, flag},一般只修改flag => {encoding:"utf8", mode:0666, flag:"a"}

                    第四个参数:回调函数,callback(err),err包含写入失败时的错误信息

                【注】

                    1. 直接打开文件默认是 w 模式,所以如果文件存在,该方法写入的内容会覆盖旧的文件内容。

                    2. 该方法一般用在fs.open方法内部

               异步写入

        fs.open("./Nodejs/input.txt", "w", function(err, fd){
            if(err){
                return console.error(err);
            }
            for(var i = 0; i <= 3; i++){
                fs.writeFile("./Nodejs/input.txt", `我是${i}个学生\n`, {encoding:"utf8", mode:0666, flag:"a"}, function(e){
                    if(e){
                        return console.log(e);
                    }
                })
                console.log("ok")
            }
        }) 

          等价于:

        var fs = require("fs");
        fs.writeFile("./Nodejs/filesystem/hello_1.txt", "这是简单文件的写入", function(err){
            if(err){
                return err;
            }else{
                console.log("文件写入成功~~")
            }
        })    

    同步写入

        var fd = fs.openSync('./simpleSync.txt', 'w')
        fs.writeFileSync(fd, '我是简单文件同步第一句!\n', function(err){
            if(err){
                console.log(err)
                return
            }
            console.log('写入文件成功!')
        })

        等价于

         var fs = require("fs");
        fs.writeFileSync("./Nodejs/filesystem/hello_1.txt", "这是简单文件的写入");
        4. 流式文件写入
    上述同步和异步以及简单文件写入都是一次性的完成写入操作,当写入的文件很大时,一次性写入会占用大量计算机内存,这样做不安全
    因此,对于大量数据的写入,我们采用流式文件写入,流式文件在读取和写入时会将大型文件分成若干小节,分小节逐步去读取和写入
         示例:
        // 流式文件写入
        var fs = require("fs");
        // 1. 创建一个写入文件流
        var ws = fs.createWriteStream("./Nodejs/filesystem/hel_2.txt");
        // 创建时间监听流的打开和关闭
        ws.once("open", function(){
            console.log("流打开了~~~");
        })
        ws.once("close", function(){
            console.log("流关闭了~~~");
        })

        // 2. 向文件中写入数据, 以ws.end();
        ws.write("我是熊大~\n");
        ws.write("我是熊二~\n");
        ws.write("我是熊三~\n");
        ws.write("我是熊四~\n");
        ws.end();

[D] 文件的读取

        1. 同步文件的读取

        2. 异步文件的读取

        3. 简单文件的读取

            同步读取

                示例:

        // 简单文件的同步读取
        var fs = require("fs");
        var rd = fs.readFileSync("./Nodejs/filesystem/input.txt");
         console.log(rd.toString());

            异步读取:

    示例:

        // 简单文件的异步读取
        var fs = require("fs");
        var rd = fs.readFile("./Nodejs/filesystem/input.txt", function(err,rd){
            if(err){
                return err;
            }
            console.log(rd.toString());
        });

        4. 流式文件读取

                示例:

         var fs = require("fs");
        // 1. 创建读取文件流
         var rs = fs.createReadStream("./Nodejs/filesystem/timg.jpg");

        // 2. 创建读取流的打开和关闭监听事件
        rs.once("open", function(){
            console.log("流打开了~~");
        })
        rs.once("close", function(){
            console.log("流关闭了~~");
        })

        // 3. 如果要读取一个可读流的数据,必须为这个可读流绑定一个data事件,data事件绑定完毕,他会自动读取数据
        // 每次读取的文件dt长度为65536
        rs.on("data", function(dt){
            console.log(dt);
        })

        // 简易写法
        var fs = require("fs");
        // 1. 创建一个可读流
        var rd = fs.createReadStream("./Nodejs/filesystem/timg.jpg");
        // 创建一个可写流
         var ws = fs.createWriteStream("./Nodejs/filesystem/mn.jpg");
        rd.pipe(ws);

[E]  Stream(流)

        1. 简介

    Stream 是一个抽象接口,Node 中有很多对象实现了这个接口。例如,对http 服务器发起请求的request 对象就是一个 Stream,还有stdout(标准输出)。

        2. 所有的 Stream 对象都是 EventEmitter 的实例

    常用的事件有:

      data - 当有数据可读时触发。

      end - 没有更多的数据可读时触发。

      error - 在接收和写入过程中发生错误时触发。

      finish - 所有数据已被写入到底层系统时触发。

        3. 读取流 —— createReadStream

    1. 创建一个可读流    

      var rs = fs.createReadStream('./input.txt')

    2. 设置字符编码

      rs.setEncoding('UTF8');

            3. 创建流打开和关闭时的监听事件

      语法:

        rs.once('open', callback)
        rs.once('close', callback)

            4. 添加监听事件 - 在读取过程中的不同阶段添加自定义操作

      语法:

        rs.on(status, callback)

      参数:

        status: 读取过程中的状态

          data - 当有数据可读时触发。

          end - 没有更多的数据可读时触发。

          error - 在接收和写入过程中发生错误时触发。

          finish - 所有数据已被写入到底层系统时触发。

                      callback: 回调函数

                            即在指定状态时出发的事件

        4. 写入流 —— createWriteStream

    1. 创建一个写入流

      var ws = fs.createWriteStream('./outtxt.txt')

    2. 写入内容并设置写入时的字符集

      ws.write(txt, 'utf-8')

    3. 标记文件末尾

      ws.end()

    4. 添加监听事件

      // 写入文件结束后调用
      ws.on('finish', () => {
        console.log('写入文件结束~~~')
      })

      // 写入文件报错时调用

      writerStream.on('error', (err) => {
        console.log(err);
      });

       

  5. 管道流 —— pipe

      管道提供了一个输出流到输入流的机制。通常我们用于从一个流中获取数据并将数据传递到另外一个流中

      通常用于复制文件,或部分复制文件

    1. 创建一个可读流

      var rs = fs.createReadStream('input.txt');

    2. 创建一个可写流

      var ws = fs.createWriteStream('output.txt');

    3. 管道读写操作

      // 读取 input.txt 文件内容,并将内容写入到 output.txt 文件中
      rs.pipe(ws);

    

  6. 链式流 —— pipe

      链式是通过连接输出流到另外一个流并创建多个流操作链的机制。链式流一般用于管道操作。

    1. 示例

      // 压缩 input.txt 文件为 input.txt.gz
      fs.createReadStream('input.txt')
      .pipe(zlib.createGzip())
      .pipe(fs.createWriteStream('input.txt.gz'));

      注:

        zlib需要先导入

          var zlib = require('zlib');

            2. 则上述的文件复制工作可简化为一个链式流

                fs.createReadStream('./inputStream.txt').pipe(fs.createWriteStream('./outtxt.txt'))

 [F] 获取文件信息 —— stat

        1. 语法

                fs.stat(path, callback)

            参数说明:

                path - 文件路径。

                callback - 回调函数,带有两个参数如:(err, stats), stats 是 fs.Stats 对象。

            stats类中的方法有:

                stats.isFile()              如果是文件返回 true,否则返回 false。

                stats.isDirectory()         如果是目录返回 true,否则返回 false。

                stats.isBlockDevice()       如果是块设备返回 true,否则返回 false。

                stats.isCharacterDevice()   如果是字符设备返回 true,否则返回 false。

                stats.isSymbolicLink()      如果是软链接返回 true,否则返回 false。

                stats.isFIFO()              如果是FIFO,返回true,否则返回 false。FIFO是UNIX中的一种特殊类型的命令管道。

                stats.isSocket()            如果是 Socket 返回 true,否则返回 false。

        2. 示例:

            var fs = require('fs');
            fs.stat('./data.js', function (err, stats) {
                if(err){
                    console.log(err)
                    return
                }
                console.log(stats.isFile());         //true
            })

[G] 删除文件 —— unlink

        1. 语法

                fs.unlink(path, callback)

            参数说明:

                path - 文件路径。

                callback - 回调函数,没有参数。

        2. 示例代码

            fs.unlink('./data.js', (err) => {
                if(err){
                    console.log(err)
                    console.log('删除文件失败~~~')
                    return
                }
                console.log('删除文件成功~~~')
            })

[H] 创建目录 —— mkdir

        1. 语法

                fs.mkdir(path[, options], callback)

            参数说明:

                path - 文件路径。

                options 参数可以是:

                    recursive - 是否以递归的方式创建目录,默认为 false。

                    mode - 设置目录权限,默认为 0777。

                callback - 回调函数,没有参数。

        2. 示例

            fs.mkdir('./Carrey', (err) => {
                if(err){
                    console.log(err)
                    console.log('创建文件夹失败了~~~')
                    return
                }
                console.log('创建文件夹成功~~~')
            })

[ I ]读取目录 —— readdir

        1. 语法

                fs.readdir(path, callback)

            参数使用说明如下:

                path - 文件路径。

                callback - 回调函数,回调函数带有两个参数err, files,err 为错误信息,files 为 目录下的文件数组列表。

        2. 示例

            fs.readdir('./Carrey', (err, files) => {
                if(err){
                    console.log(err)
                    console.log('读取文件失败了~~~')
                    return
                }
                console.log(files)
            })

[J] 删除目录 —— rmdir

        1. 语法

                fs.rmdir(path, callback)

            参数使用说明如下:

                path - 文件路径。

                callback - 回调函数,没有参数。

            注:

                该方法只能删除空的目录,当目录内部不为空时,会报错

        2. 示例

            fs.rmdir('./Carrey', (err) => {
                if(err){
                    console.log(err)
                    console.log('删除目录失败~~~')
                    return
                }
                console.log('删除目录成功~~~')
            })
 
 
原文地址:https://www.cnblogs.com/carreyBlog/p/15548903.html