02.nodejs的url、fs模块

nodejs的内置url、fs模块

前言

本文对应所有代码的github仓库是:
https://github.com/liangfenggithub/nodejsLearn.git

顺带吐槽一下,在本地利用typora写完md文档,然后粘贴到csdn中发现图片都不能直接从浏览器读取,还得一张一张从本地电脑上找到在粘贴进来,很是繁琐,真希望csdn能支持直接读取md文件本地电脑相对路径的图片。

内置模块

nodejs自带了很多封装的模块,类似Java中的类库,提供一些常用功能。

http模块

//引用模块
var http = require('http');
http.createServer(function (request, response) {
	//发送http头部
	//HTTP 状态值:200 ok
	//设置HTTP头部,状态码是200,文件类型是html,字符集是utf8
	response.writeHead(200, { "Content-Type": "text/html;charset=UTF-8" });

	//发送响应数据 "hello world"
	response.end("哈哈哈,helloworld");
}).listen(9999,"127.0.0.1");
//终端打印如下信息
console.log("server runing at http://127.0.0.1:9999")

  • createServer: 创建服务器,回调函数表示接受到请求要做的事情
  • server.listen :监听端口和ip地址

url模块

常用方法

  1. url.parse() :解析URL
  2. url.format(urlObject) :编码url 是url.parse的逆向操作
  3. url.resolve(from,to) :添加或者替换地址

在命令行中输入node可以进入交互式界面,出现>后可以直接执行js函数,类似python

1. url.parse()
url.parse("www.google.com")
//输出
Url {
  protocol: null,
  slashes: null,
  auth: null,
  host: null,
  port: null,
  hostname: null,
  hash: null,
  search: null,
  query: null,
  pathname: 'www.google.com',
  path: 'www.google.com',
  href: 'www.google.com' }

parse函数还可解析get方法的传值,比如:

> url.parse("http://www.google.com?name='abc'&age='20'")
//输出
Url {
  protocol: 'http:',
  slashes: true,
  auth: null,
  host: 'www.google.com',
  port: null,
  hostname: 'www.google.com',
  hash: null,
  search: '?name=%27abc%27&age=%2720%27',
  query: 'name=%27abc%27&age=%2720%27',
  pathname: '/',
  path: '/?name=%27abc%27&age=%2720%27',
  href: 'http://www.google.com/?name=%27abc%27&age=%2720%27' }

parse函数还有第二个参数,当为true时可以将url中的键值对用对象表示出来,方便之后的处理

> url.parse("http://www.google.com?name='abc'&age='20'",true)
Url {
  protocol: 'http:',
  slashes: true,
  auth: null,
  host: 'www.google.com',
  port: null,
  hostname: 'www.google.com',
  hash: null,
  search: '?name=%27abc%27&age=%2720%27',
  query: [Object: null prototype] { name: '\'abc\'', age: '\'20\'' },//注意这里输出是对象
  pathname: '/',
  path: '/?name=%27abc%27&age=%2720%27',
  href: 'http://www.google.com/?name=%27abc%27&age=%2720%27' }
2. url.formot()

根据对象生成url字符串,是parse的反操作。

3. url.resolve()

拼接url

url.resolve("http://www.google.com","/foo")
//输出
//http://www.google.com/foo

FS模块

FS模块是文件模块,提供js用来操作文件的能力,非常常用。

nodejs程序的特点是很多地方使用了回调函数。fs模块等这些内置模块也是如此,fs模块的很多方法的一个参数就是一个回调函数,所有处理结果都在这个回调函数中获得,回调函数的参数一般有多个,这些参数中肯定有一个err,err是错误标志,如果为false说明方法执行成功,可以继续处理,否则直接停止运行。

fs.stat 文件目录判断

stat函数用来检测是文件还是目录,通过回调函数的参数stats中的方法isFile()和isDirectory()方法的返回值来判断是文件还是目录。

showcode

const fs = require("fs");
fs.stat("01.server.js", (err, status) => {
  if (err) {
    console.log(err);
  } else {
    console.log(status);
    console.log(`文件:${status.isFile()}`)
    console.log(`目录:${status.isDirectory()}`)
  }
})

执行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SGcVXsqI-1575688874922)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20191206182955802.png)]

fs.mkdir 创建目录

mkdir类似linux中mkdir目录,用于创建目录。

fs.mkdir(path,mode,callback)
  • path 要创建的目录路径
  • mode 目录权限,默认0777
  • callback 回调函数,一个异常参数err
const fs = require("fs")

fs.mkdir("logs", (err) => {
  if (err) {
    console.log("创建目录发生错误", err)
  } else {
    console.log("成功创建目录:logs")
  }
})

C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20191206183327724.png

fs.writeFile 创建文件

writeFile实现创建文件并写入内容。

fs.writeFile(filename,data,options,callback	)
  • filename (String) 文件名称
  • data (String|Buffer)要写入的内容,可以是字符串或者buffer数据
  • options (Object) option数组对象,包含
    • encoding (string) 可选值,默认是“urft8” ,当data使buffer时,该值应该为 ignored。
    • mode (Number) 文件读写权限
    • flag (String) 默认值为“w”
  • callback回调函数,一个异常参数err

writeFile实现创建文件并写入内容。

var fs = require("fs");
var data = "hello world"
var path = "logs/20191206.log"
fs.writeFile(path, data, (err) => {
  if (err) {
    console.log("写入错误,error:", err)
  } else {
    console.log("成功写入文件")
  }
})

注意,如果路径写为logs/20191206.log是从根目录作为相对路径,如果写为/logs/20191206.log,则是以磁盘根目录为路径,一个斜杆不可忽视。

C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20191206185358646.png

fs.appendFile 追加文件内容

appendFile用于为现有文件追加文件内容,最常见就是log文件,只要有新的日志信息就追加到log文件中。

var fs = require("fs")
var path = "logs/20191206.log"
fs.appendFile(path, "哈哈哈哈", (err) => {
  if (err) {
    console.log("追加文件出错,错误原因:", err);
  } else {
    console.log("文件追加成功!")
  }
})

C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20191206185524487.png

fs.readFile 读取文件

以指定的编码格式读取文件

const fs = require("fs");
var path = "logs/20191206.log"

fs.readFile(path, "utf8", (err, data) => {//第二个参数是编码格式
  if (err) {
    console.log("读物文件出错,error:", err);
  } else {
    console.log("文件内容是:", data);
  }
})

在这里插入图片描述

fs.readdir 读取目录

读取指定目录下的文件和目录,返回结果是一个数组,数组元素是字符串形式的目录名或者文件名。

const fs = require("fs");
fs.readdir("logs", (err, files) => {
  if (err) {
    console.log("读取目录失败,error:", err)
  } else {
    console.log("该目录下内容是:", files)
  }
})

C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20191206190543610.png

fs.rename 重命名

const fs = require("fs")
//参数:源名称、目的名称、回调函数
fs.rename("logs/test", "logs/test2", (err) => {
  if (err) {
    console.log("重命名失败,error:", err);
  } else {
    console.log("重命名成功");
  }
})

C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20191206191037588.png

fs.rm dir 删除目录

rm方法只能删除目录,不能删除文件,删除文件使用unlink方法。

const fs = require("fs");
fs.rmdir("logs/test2", (err) => {
  if (err) {
    console.log("删除指定目录失败,error:", err);
  } else {
    console.log("成功删除了目录!");
  }
})

C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20191206191316432.png

fs.unlink 删除文件

const fs = require("fs");
let filename = "test.html"
fs.unlink(`logs/${filename}`, (err) => {
  if (err) {
    console.log(`删除文件${filename}失败,error:`, err)
  } else {
    console.log(`成功删除了文件:${filename}`)
  }
})

C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20191206191721165.png

小练习

练习1:文件上传,判断upload文件夹是否存在,如果不存在就创建

//练习: 判断服务器是否有upload文件夹,用于上传图片的存放,如果没有该文件夹自动创建
const fs = require("fs");
let path = "logs/upload"
//文件夹创建函数
let createDir = () => {
  fs.mkdir(path, (err) => {
    if (err) {
      console.log(`创建${path}失败!error:`, err);
    } else {
      console.log(`${path}创建成功!`);
    }
  })
}


fs.stat(path, (err, status) => {
  if (err) {//如果读不到指定文件名说明不存在,手动创建
    console.log(`文件夹${path}不存在,开始手动创建。。。`);
    createDir();
  } else {
    if (status.isDirectory()) {
      console.log(`${path}存在!`);
    } else {//如果读到的不是文件夹,则手动创建
      createDir();
    }
  }
})

C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20191206194407689.png
练习2:找出html目录下面的所有的目录,然后打印出来

//练习程序:读取指定目录下的所有目录
const fs = require("fs");

let readDir = (path) => {
  let dirArray = [];
  fs.readdir(path, (err, files) => {
    if (err) {
      console.log("目录读取失败,error:", err);

    } else {
      //这里的files是一个字符串组成的数组,有目录有文件,需要手动判断下。
      files.forEach((file) => {

        //拼接相对路径,如果是目录则继续读取
        let pathTarget = `${path}/${file}`
        //判断是目录还是文件
        fs.stat(pathTarget, (err, status) => {
          if (err) {
            console.log(`读取目录${file}失败,error:`, err)
          } else {
            if (status.isDirectory()) {
              dirArray.push(file);
              // 打印目录
              console.log(`|-${file}\r\n`);
              //递归读取
              readDir(pathTarget)
            }
            if (status.isFile()) {
              //打印文件名
              console.log(`|--${file}\r\n`);
            }

            //疑问, 如何判断递归读取完毕了?
            //      回调函数如何判断函数已经执行完毕了呢?
            //      也就是何时打印出dirArray呢?
          }
        })
      })
    }
  })
}

//开始执行
readDir("./");

在这里插入图片描述

fs.createReadStream 从文件流中读取数据

文件流读取是一块一块(chunk)读取的,构建三个事件监听函数(data、error、end)分别处理数据到达、数据错误和数据读取完毕的事件。

为实验大数据是分块读取的效果,我们可以构建一个大文本文件,

//构造大文本文件的辅助文件,修改程序中 lineCnt可以修改创建文件的行数
const line = 10000;//要创建的行数
const bigfile = "./logs/bigdata.json";//要操作的文件
const fs = require("fs");
fs.stat(bigfile, (err, status) => {
  if (err) {
    console.log(`指定路径文件${bigfile}不存在,开始创建...`);
    //出错说明该文件不存在,手动创建之
    fs.writeFile(bigfile, `大文本文件,一共${line}行`, (err) => {
      if (err) {
        console.log("写文件出错,请检查程序")
      } else {
        //追加大量文本信息
        let lineCnt = line;//行数限制,也是递归终止检测限制
        let appText = () => {
          fs.appendFile(bigfile, "i am append text,ha ha ha\r\n ", (err) => {
            if (err) {
              console.log("追加文件内容出错,请检查程序");
            } else {
              if (--lineCnt > 0) {
                //递归追加
                appText();
              } else {
                console.log("大文件创建完毕,一共创建了" + line + "行");
              }
            }
          })
        }
        //开始执行文本追加
        appText();
      }
    })
  } else {
    console.log(`指定路径文件${bigfile}存在,程序退出`);
    return;
  }
})

C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20191207104812955.pn
文件读取测试程序,可以看出每次读取最大数量是65536个字节,如果超出,则分多次进行读取。

const fs = require('fs');
const bigfile = "./logs/bigdata.json";
var fileReadStream = fs.createReadStream(bigfile)
let count = 0;//chunk计算
let str = "";//目的字符串
//流读取时间函数
fileReadStream.on("data", (chunk) => {
  count++;
  console.log(`${count}  接受到长度为:${chunk.length}`);
  str += chunk;
})
//流读取完成监听函数
fileReadStream.on("end", () => {
  console.log("---结束---");
  console.log("接受总次数为:", count);
  // console.log("最终接受到所有数据是:", str) //太大了,不好显示
})
//流读取错误监听函数
fileReadStream.on("error", (err) => {
  console.log("读取出错,error:", err)
})

C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20191207104905590.png

fs.createWriteStream 流式写入文件

与上述fs.createReadStream读取文件相反,fs.createWriteStream为流式写入文件。

流式写入文件可以替代上述的大文件创建程序

const fs = require("fs");
let fileName = "./logs/writeFile.data"
let createWriteStream = fs.createWriteStream(fileName);
createWriteStream.write("我是通过流写入的数据\r\n", "UTF8");//以指定编码写入内容
createWriteStream.end();//标记文件末尾
createWriteStream.on("error", (err) => {
  console.log("文件写入出错,error:", err);
})
createWriteStream.on("finish", (err) => {
  console.log("文件写入完成!");
})
console.log("程序执行完毕");//注意:因为上述监听函数都是异步,因此这行函数被先执行。

C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20191207110149546.png

管道流 pipe函数

管道在linux系统 中是一个重要的概念,nodejs的文件操作中也就有管道的功能,具体作用就是类似一个水管一样把一个输入直接传递到一个输出中。输入输出可以是文件,也可以是网络等。

下面以一个文件操作来演示。

const fs = require("fs");
const readFile = "./logs/bigdata.json";
const writeFile = "./logs/writeFile.data";
let readStream = fs.createReadStream(readFile);
let writeStream = fs.createWriteStream(writeFile);

//利用管道将文件流入输出中
readStream.pipe(writeStream);
console.log("程序执行完毕");

(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20191207111032304.png)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值