文件操作

文件编码问题

1、node在读取文件的时候是不支持读取GBK编码的文件,一般都是utf8,所以有的时候我们需要读取GBK文件时,可以借助第三方插件iconv-lite来转换成我们所需要的编码形式。
  • 1、https://www.npmjs.com/package/iconv-lite 首先去官网下载iconv-lite这个模块,然后用require引入该模块。只要是文件操作,都要引用fspath两个模块
/**
 * 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) + '%');
    });
    
  }

});


你可能感兴趣的:(文件操作)