美文网首页
文件操作

文件操作

作者: 不要和我名字一样 | 来源:发表于2017-06-07 18:05 被阅读193次

    文件编码问题

    1、node在读取文件的时候是不支持读取GBK编码的文件,一般都是utf8,所以有的时候我们需要读取GBK文件时,可以借助第三方插件iconv-lite来转换成我们所需要的编码形式。
    /**
     * Created by 黄森 on 2017/6/7.
     */
    const fs = require('fs');
    const path = require('path');
    const iconv = require('iconv-lite');
    
    fs.readFile(path.join(__dirname,'./血染的风采.lrc'),(error,data)=>{
        //decode中两个参数,第一个为你要转化的buffer,第二个为你要转化的编码方式
        console.log(iconv.decode(data,'GBK'));
        // console.log(data.toString('GBK'));
    });
    

    这样就可以将我们所读取的buffer转化成GBK格式的文件,如果直接使用data.toString('GBK')的话会提示这样的错误:

    buffer.js:480
              throw new TypeError('Unknown encoding: ' + encoding);
              ^
    
    TypeError: Unknown encoding: gbk
        at Buffer.slowToString (buffer.js:480:17)
        at Buffer.toString (buffer.js:493:27)
        at fs.readFile (F:\WebstormProjects\untitled\06.js:10:22)
        at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:446:3)
    
    

    小小案例(动态显示歌词)

    lrc的歌词按照时间顺序将对应的歌词在控制台显示

    /**
     * Created by 黄森 on 2017/6/7.
     */
    // 动态显示歌词
    
    //引入模块
    const fs = require('fs');
    const path = require('path');
    const iconv = require('iconv-lite');
    
    fs.readFile(path.join(__dirname,'./血染的风采.lrc'),(error,data)=>{
        //按照换行分割歌词
        var lines = iconv.decode(data, 'gbk').split('\n');
        // console.log(lines.length);
        //正则匹配歌词
        var regex = /\[(\d{2})\:(\d{2})\.(\d{2})\]\s(.+)/;
        //计时间差
        var begin = new Date().getTime();
        // 遍历
        lines.forEach((line) => {
            // [00:32.67] 也许我告别 将不再回来
            var matches = regex.exec(line);
            if (matches) {
                var m = parseFloat(matches[1]);
                var s = parseFloat(matches[2]);
                var f = parseFloat(matches[3]);
                var lyric = matches[4]; // 当前行歌词不是立即执行
                // 由于下达输出任务的时刻不同
    
                // 由于代码执行需要消耗时间,所以要减去执行时间
                var offset = new Date().getTime() - begin;
                setTimeout(() => {
                    console.log(lyric);
                }, m * 60 * 1000 + s * 1000 + f - offset);
            } else {
                // 不是一行歌词
                console.log(line);
            }
        });
    });
    

    但是这种方式是一下把所有的内容全部读取到内存中,文件比较大的话就会出现卡顿,node就提供了一个读取单行文本的api

    2、readline模块逐行读取文本

    下面用readline模块改版读取歌词

    /**
     * Created by 黄森 on 2017/6/7.
     */
    // readline动态显示歌词
    
    const fs = require('fs');
    const path = require('path');
    const iconv = require('iconv-lite');
    const readline = require('readline');
    
    var filename = path.join(__dirname, './../lyrics/血染的风采.lrc');
    
    var streamReader = fs.createReadStream(filename)
      .pipe(iconv.decodeStream('gbk'));
    
    // 利用readline读取
    var rl = readline.createInterface({ input: streamReader });
    
    var begin = new Date().getTime();
    rl.on('line', (line) => {
      task(line, begin);
    });
    
    var regex = /\[(\d{2})\:(\d{2})\.(\d{2})\]\s(.+)/;
    
    //输出歌词,抽出单独方法
    function task(line, begin) {
      // [00:32.67] 也许我告别 将不再回来
      var matches = regex.exec(line);
      if (matches) {
        var m = parseFloat(matches[1]);
        var s = parseFloat(matches[2]);
        var f = parseFloat(matches[3]);
        var lyric = matches[4]; // 当前行歌词不是立即执行
        // 由于下达输出任务的时刻不同
        var offset = new Date().getTime() - begin;
        setTimeout(() => {
          console.log(lyric);
        }, m * 60 * 1000 + s * 1000 + f - offset);
      } else {
        // 不是一行歌词
        console.log(line);
      }
    }
    
    3、文件写入
    异步文件写入
    fs.writeFile(file,data[,option],callback(err))
    同步文件写入
    fs.writeFileSync(file,data,[,option])
    流式文件写
    fs.createWriteStream(path[,option])
    默认写入操作是覆盖源文件
    异步追加
    fs.appendFile(file,data[,options],callback(err))
    同步追加
    fs.appendFileSync(file,data[,options])
    
    • 1)文件异步写入
    /**
     * Created by 黄森 on 2017/6/7.
     */
    const fs = require('fs');
    const path = require('path');
    
    //JSON.stringify({id:10})序列化
    //JSON.parse  反序列化
    fs.writeFile(path.join(__dirname,'./test.txt'),JSON.stringify({id:10}),(err)=>{
        if(err){
            //读文件是不存在报错
            //意外错误
            //文件权限问题
            //文件夹找不到(不会自动创建文件夹)
            console.log('error')
        }else {
            console.log('success');
        }
    });
    
    

    fs.writeFile()方法中系一个参数为路径,第二个参数是要写入的内容,第三个参数是回掉函数。JSON.stringify({id:10})序列化,将一个对象转化为JSON,JSON.parse 反序列化,将JSON转化为object.
    同步写入fs.writeFileSync();和异步是一样的。
    因为文件的写入是覆盖源文件,所以就又文件追加的这样一个需求,node提供了fs.appendFile()这样一个函数,可以在原有的基础上追加文件内容。里面的参数和fs.writeFile()是一样的。

    • 2)文件同步写入
      fs.appendFileSync(file,data[,options]),同步写入和异步是一样的,参数都相同
    4、其他文件操作
    重命名文件或目录/移动文件
    fs.rename(oldPath,newPath,callback)
    fs.renameSync(oldPath,newPath)
    删除文件
    fs.unlink(path,callback(err))
    fs.unlinkSync(path)
    验证路径是否存在(过时的API,用stat代替)
    fs.exists(path,callback(exists))
    fs.existsSync(path) // => 返回布尔类型 exists
    获取文件信息
    fs.stat(path,callback(err,stats))
    fs.statSync(path) // => 返回一个fs.Stats实例
    移动文件
    fs.rename(oldPath,newPath)
    

    对目录的操作

    创建一个目录
    fs.mkdir(path[,model],callback)
    fs.mkdirSync(path[,model])
    删除一个空目录
    fs.rmdir(path,callback)
    fs.rmdirSync(path)
    读取一个目录
    fs.readdir(path,callback(err,files))
    fs.readdirSync(path) // => 返回files
    
    案例:打印目录列表
    /**
     * Created by 黄森 on 2017/6/7.
     */
    //打印当前目录所有文件
    
    const fs = require('fs');
    const path = require('path');
    require('./proto.js'); //格式化时间的js
    
    
    //获取当前有没有传入目标路径
    
    var target = path.join(__dirname,process.argv[2] || './');
    
    fs.readdir(target,(error,files)=>{
       files.forEach(files=>{
           // console.log(path.join(target,files));
           fs.stat(path.join(target,files),(err,stats)=>{
               console.log(`${stats.mtime.format('yyyy/MM/dd HH:mm')}\t${stats.size}\t${files}`)
           })
       })
    });
    
    5、创建文件夹
    /**
     * Created by 黄森 on 2017/6/8.
     */
    //创建文件夹
    const fs = require('fs');
    const path =require('path');
    
    fs.mkdir(path.join(__dirname,'demo'));
    

    文件夹路径过长,无法拷贝问题

    监视文件变化:
    fs.watchFile(filename[, options], listener(curr,prev))
    options:{persistent,interval}
    fs.watch(filename[,options][,listener])
    

    利用文件监视实现自动 markdown 文件转换
    https://github.com/chjj/marked
    https://github.com/Browsersync/browser-sync
    大文件拷贝
    https://github.com/tj/node-progress

    6、文件的拷贝
    // 文件的复制
    
    const fs = require('fs');
    const path = require('path');
    
    console.time('read');//计算时间
    fs.readFile('C:\\Users\\iceStone\\Desktop\\1.iso', (err, data) => {
      if (err) {
        throw err
      }
      console.timeEnd('read');
      console.time('write');
      // 读取完文件拿到
      fs.writeFile('C:\\Users\\iceStone\\Desktop\\2.iso', data, err=> {
        if (err) {
          throw err
        }
        console.timeEnd('write');
        console.log('拷贝完成');
      });
    });
    

    这种方式的话,文件太大,我们电脑的内存就会受不了,所以就会使用文件流的方式拷贝文件

    // 文件流的方式的复制
    
    const fs = require('fs');
    const path = require('path');
    
    // 创建文件的读取流,并没有读出正式的数据,开始了读取文件的任务()
    var reader = fs.createReadStream('C:\\Users\\iceStone\\Desktop\\1.itcast');
    
    // 磁盘: 7200转 6100转 转速越快 读写越快 资源消耗更大
    fs.stat('C:\\Users\\iceStone\\Desktop\\1.itcast', (err, stats) => {
    
      if (stats) {
        
        var readTotal = 0;
        reader.on('data', (chunk) => { 
          // chunk是一个buffer(字节数组)
          console.log('读了一点 进度:' + ((readTotal += chunk.length) / stats.size * 100) + '%');
        });
        
      }
    
    });
    
    
    

    相关文章

      网友评论

          本文标题:文件操作

          本文链接:https://www.haomeiwen.com/subject/lnsofxtx.html