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模块
常用方法
- url.parse() :解析URL
- url.format(urlObject) :编码url 是url.parse的逆向操作
- 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")
}
})
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
,则是以磁盘根目录为路径,一个斜杆不可忽视。
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("文件追加成功!")
}
})
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)
}
})
fs.rename 重命名
const fs = require("fs")
//参数:源名称、目的名称、回调函数
fs.rename("logs/test", "logs/test2", (err) => {
if (err) {
console.log("重命名失败,error:", err);
} else {
console.log("重命名成功");
}
})
fs.rm dir 删除目录
rm方法只能删除目录,不能删除文件,删除文件使用unlink方法。
const fs = require("fs");
fs.rmdir("logs/test2", (err) => {
if (err) {
console.log("删除指定目录失败,error:", err);
} else {
console.log("成功删除了目录!");
}
})
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}`)
}
})
小练习
练习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();
}
}
})
练习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;
}
})
文件读取测试程序,可以看出每次读取最大数量是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)
})
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("程序执行完毕");//注意:因为上述监听函数都是异步,因此这行函数被先执行。
管道流 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("程序执行完毕");
(