nodejs_2

包与npm

nodejs中除了它自己提供的核心模块之外,我们还可以自定义模块,也可以使用第三方模块。nodejs中的第三方模块是由组成,可以通过包来对一组具有相互依赖关系的模块进行统一管理。

从上面这个图可以看出,一个包是由多个模块组成的,模块之间具有相互依赖的关系。

完成符合CommonJS规范的包目录一般包含如下这些文件:

  • package.json:包描述文件
  • bin:存放可执行二进制文件的目录
  • lib:存放javascript代码的目录
  • doc :存放文档的目录

第三方模块

package.json

  • dependencies:配置当前程序所依赖的其他包

  • devDependencies:配置当前程序所依赖的其他包(主要是指工具类的配置)

上面版本数字之前的符号释义:

  • ^:表示第一位版本号不变,后面两位取最新
  • ~:表示前两位不变,最后一位取最新
  • *:表示全部取最新

fs模块

/**
 * 1.fs.stat  检测是文件还是目录
 * 2.fs.mkdir  创建目录
 * 3.fs.writeFile  创建写入文件
 * 4.fs.appendFile  追加文件
 * 5.fs.readFile  读取文件
 * 6.fs.readdir  读取目录
 * 7.fs.rename  重命名
 * 8.fs.rmdir  删除目录
 * 9.fs.unlink  删除文件
 */

const fs = require('fs');

// 1 fs.stat  检测是文件还是目录
fs.stat('./../demo01_http', (err, data) => {
  if (err) {
    console.log(err);
    return;
  }
  console.log(`是文件:${data.isFile()}`);
  console.log(`是目录:${data.isDirectory()}`);
})

// 2.fs.mkdir  创建目录

/**
 * 参数说明:
 * 1 path:将创建的目录路径
 * 2 mode:目录权限(读写权限,如777),可不写
 * 3 callback:回调,传递异常参数err
 */
fs.mkdir('./css', (err) => {
  if (err) {
    console.log(err);
    return;
  }
  console.log("创建成功");
})

// 3.fs.writeFile  创建写入文件
/**
 * 参数说明:
 * 1 path:将创建的文件路径
 * 2 data:在创建好的文件中写入的内容
 * 3 options:  可省略
 *  - encoding:string,可选值,默认utf-8
 *  - mode:number,文件的读写权限,默认438
 *  - flag:string,默认值‘w’
 * 4 callback:回调,传递异常参数err
 */

//  ⚠️:如果创建写入的文件已存在,那么后面创建的这个文件的写入内容会覆盖之前的文件内容
fs.writeFile('./html/a.html', 'hello world', (err) => {
  if (err) {
    console.log(err);
    return;
  }
  console.log("创建写入文件成功");
})


// 4.fs.appendFile  追加文件
// ⚠️:如果文件存在的话,会在该文件内容后面追加内容
fs.appendFile('./css/base.css', 'body{background: pink}', (err) => {
  if (err) {
    console.log(err);
    return;
  }
  console.log("appendFile成功");
})

// 5.fs.readFile  读取文件
fs.readFile('./html/a.html', (err, data) => {
  if (err) {
    console.log(err); // 路径错误时:[Error: ENOENT: no such file or directory, open './aaa/a.html'] 
    return;
  }
  console.log(data); // <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>
  // 将buffer转换成string类型
  console.log(data.toString()); // hello world
})

// 6.fs.readdir  读取目录
fs.readdir('../demo05_fs', (err, data) => {
  if (err) {
    console.log(err);
    return;
  }
  console.log(data); // [ 'app.js', 'css', 'html', 'package.json' ] 
})

// 7.fs.rename  重命名
/**
 * 功能:
 * 1: 表示重命名
 * 2: 表示移动文件
 */
// 1
fs.rename('./css/aaa.css', './css/index.css', (err) => {
  if (err) {
    console.log(err);
    return;
  }
  console.log('重命名成功');
})

// 2
fs.rename('./css/index.css', './html/index.css', (err) => {
  if (err) {
    console.log(err);
    return;
  }
  console.log('移动文件成功');
})


// 8.fs.rmdir  删除目录
// ⚠️:如果目录中有文件的话是删除不了这个目录的,需要先通过fs.unlink()删除了文件之后再删除目录
fs.rmdir('./aaa', (err) => {
  if (err) {
    console.log(err);
    return;
  }
  console.log('删除目录成功');
})

// 9.fs.unlink  删除文件
fs.unlink('./aaa/index.html', (err) => {
  if (err) {
    console.log(err);
    return;
  }
  console.log('删除文件成功');
})

fs demo

  • 判断服务器上有没有upload目录,没有的话创建这个目录,有的话不做操作
// 判断服务器上有没有upload目录,没有的话创建这个目录,有的话不做操作
const fs = require('fs');
var path = './upload';

fs.stat(path, (err, data) => {
  if (err) {
    // 如果目录或文件不存在,执行创建目录
    mkdir(path);
    return;
  }
  if (!data.isDirectory()) {
    // 如果是个文件,需要先删除这个文件,再执行创建目录
    fs.unlink(path, (err) => {
      if (!err) {
        mkdir(path);
      } else {
        console.log("请检测传入的数据是否正确");
      }
    })
  }
})

// 创建目录的方法
function mkdir(dir) {
  fs.mkdir(dir, (err) => {
    if (err) {
      console.log(err);
      return;
    }
  })
}

要创建多级目录还可以在npm里面搜索mkdirp这个模块,它可以创建多级目录

  • wwwroot文件夹下面有images,css,js以及index.html,找出wwwroot目录下面的所有目录

⚠️用下面的这种方法来实现是不对的

var fs = require('fs');

var path = './wwwroot';
var dirArr = [];
fs.readdir(path, (err, data) => {
  if (err) {
    console.log(err);
    return;
  }

  for (var i = 0; i < data.length; i++) {
    fs.stat(path + '/' + data[i], (error, stats) => {
      if (stats.isDirectory()) {
        dirArr.push(data[i]);
      }
    })
  }
  console.log(dirArr);     //[]
})

console.log(dirArr);        //[]

因为这里的这个for循环里面的fs.stat(),存在异步的问题,所以在后面打印dirArr时,两个都是空的

改写:通过匿名自执行函数实现递归

// wwwroot文件夹下面有images,css,js以及index.html,找出wwwroot目录下面的所有目录
var fs = require('fs');

var path = './wwwroot';
var dirArr = [];
fs.readdir(path, (err, data) => {
  if (err) {
    console.log(err);
    return;
  }

  // 通过匿名自执行函数实现递归
  // 首先检测第0个,检测完成后在内部再调用这个方法取检测下一个

  (function getDir(i) {
    if (i == data.length) { // 执行完成
      console.log(dirArr);
      return;
    }
    fs.stat(path + '/' + data[i], (error, stats) => {
      if (stats.isDirectory()) {
        dirArr.push(data[i]);
      }
      getDir(i + 1);
    })
  })(0)
})

获取异步方法里面的数据demo

这里有两种方法来实现

// 外部获取异步方法里面的数据
function getData(callback) {
  setTimeout(function () {
    var name = 'doris'
    callback(name);
  }, 1000)
}

// 1 ES6之前可以通过回调函数来获取
getData(function (aaa) {
  console.log(aaa);
})

// 2 ES6之后可以用promise来获取
/**
 * promise来处理异步,有两个参数:
 * resolve:成功的回调函数
 * reject:失败的回调函数
 */

var p = new Promise(function (resolve, reject) {
  setTimeout(function () {
    var name = 'doris 11'
    resolve(name);
  }, 1000)
})

// 获取里面的数据
p.then(function(data){
  console.log(data);
});

也可以对上面的第二种方法(promise)来进行一个简化封装

// 2 ES6之后可以用promise来获取
/**
 * promise来处理异步,有两个参数:
 * resolve:成功的回调函数
 * reject:失败的回调函数
 */

function getData(resolve, reject) {
  setTimeout(function () {
    var name = 'doris 11'
    resolve(name);
  }, 1000)
}

var p = new Promise(getData);

// 获取里面的数据
p.then(function(data){
  console.log(data);
});

async/await

  • async

    用于申明一个异步的function(让方法变成异步)

  • await

    用于等待一个异步方法执行完成(但是必须用在async异步方法里面,否则报错

function aaa(){
  return "Hihi~";
}
console.log(aaa());     // Hihi~

async function bbb(){
  return "Hihihi~";
}
console.log(bbb());     // Promise { 'Hihihi~' }


// async function bbb(){
//   return "Hihihi~";
// }
// console.log(await bbb());    // 这样会报错。因为await必须得用在async中

async function bbb(){
  return "HihihiHi~";
}
async function main(){
  var data = await bbb();     // 获取异步方法里面得数据
  console.log(data);          // HihihiHi~
}
main();

用async/await方法改写之前的读取目录的demo

const fs = require('fs');

// 1 定义一个 isDir 方法,判断一个资源到底是目录还是文件

async function isDir(path) {
  return new Promise((resolve, reject) => {
    fs.stat(path, (error, stats) => {
      if (error) {
        console.log(error);
        reject(error);
        return;
      }
      if (stats.isDirectory()) {
        resolve(true)
      } else {
        resolve(false);
      }
    })
  })
}

// 2 获取wwwroot里面的所有资源,循环遍历
var path = './wwwroot';
var dirArr = [];

function main() {
  // 注意async加的地方必须得是await方法的外部(离 await 最近的方法前面加 async)
  fs.readdir(path, async (err, data) => {
    if (err) {
      console.log(err);
      return;
    }
    for (var i = 0; i < data.length; i++) {
      if (await isDir(path + '/' + data[i])) {
        dirArr.push(data[i]);
      }
    }
    console.log(dirArr); // [ 'css', 'images', 'js', 'xxx' ]
  })
}

main();

以流的方式来读取/写入文件

比较大的文件时可以用这个方法

  • 以流的方式读取
const fs = require('fs');

var readStream = fs.createReadStream('./data/input.txt');

var count = 0;
var str = '';
readStream.on('data', (data) => {
  str += data;
  count++;
})

readStream.on('end', () => {
  console.log(str);
  console.log(count);   // 2  这里这个2的意思是以流的方式读取了两次
})

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

  • 以流的方式写入
const fs = require('fs');

var str = '';

for (var i = 0; i < 500; i++) {
  str += 'hihihihihihihihihihihihi~\n';
}

var writeStream = fs.createWriteStream('./data/output.txt');

writeStream.write(str);

// 标记写入完成
writeStream.end();

writeStream.on('finish', ()=>{
  console.log('写入完成');
})

  • 管道流(复制)
const fs = require('fs');

var readStream = fs.createReadStream('./pic.png');

var writeStream = fs.createWriteStream('./data/pic.png');

readStream.pipe(writeStream);

猜你喜欢

转载自blog.csdn.net/LLLLLLLLLLe/article/details/109569255