Node.js躬行记(2)——文件系统和网络

简介:   fs模块可与文件系统进行交互,封装了常规的POSIX函数。POSIX(Portable Operating System Interface,可移植操作系统接口)是UNIX系统的一个设计标准。fs模块提供了多个操作目录和文件的方法,大多会有同步和异步两种版本,同步的方法名称会以Sync为后缀。

一、文件系统


  fs模块可与文件系统进行交互,封装了常规的POSIX函数。POSIX(Portable Operating System Interface,可移植操作系统接口)是UNIX系统的一个设计标准。fs模块提供了多个操作目录和文件的方法,大多会有同步和异步两种版本,同步的方法名称会以Sync为后缀。

1)目录处理

  fs模块的readdir()方法可异步的读取目录内容,回调函数包含两个参数,第一个是错误对象,第二个是一个包含文件名称的数组,对应的同步方法是readdirSync()。在下面的示例中,当前目录包含两个文件,上一级目录包含一个目录名称。


const fs = require('fs');
fs.readdir('./', (err, files) => {
  console.log(files);        //[ 'demo.txt', 'index.js' ]
});
fs.readdir('../', (err, files) => {
  console.log(files);        //[ '1' ]
});


  其它处理目录的方法还有opendir()、mkdir()等。

2)读写文件

  在fs模块中,可使用批量方法readFile()将文件内容一次性的加载到内存中,如下所示。

const fs = require('fs');
fs.readFile('./origin.txt', (err, buf) => {
  console.log(buf.toString());        //"hello Node.js"
});

  对应的写入方法是writeFile(),如下所示,文件路径、写入内容和回调函数是必传的参数。如果文件不存在,那么会自动创建。

fs.writeFile('./target.txt', 'hello Node.js', (err) => {
  if (err) throw err;
  console.log('文件已被保存');
});

  当文件很大时,像上面这样直接读取会有问题,可以改用流式方法createReadStream(),分批次的读取文件,如下所示,每次只读7个字节的内容。


const readable = fs.createReadStream('./origin.txt', {highWaterMark: 7});
readable.on("data", (chunk) => {
  /*************/
  /* "hello N"
  /* "ode.js"
  /************/
  console.log(chunk.toString());
});


  通过管道方法pipe()将origin.txt中的内容写入到target-stream.txt中,如下所示,对于不存在的文件,也会自动创建。

const writable = fs.createWriteStream('./target-stream.txt');
readable.pipe(writable);

3)文件描述

  fs模块的stat()方法可读取文件的描述信息,如下所示。

fs.stat('./demo.txt', (err, stats) => {
  console.log(stats);
});

  回调函数中的stats参数是一个fs.Stats对象,其属性如下所示。它还包含一些判断方法,例如isDirectory()、isFile()等。


Stats {
  dev: 195650,
  mode: 33206,
  nlink: 1,
  uid: 0,
  gid: 0,
  rdev: 0,
  blksize: undefined,
  ino: 36873221949682120,
  size: 13,
  blocks: undefined,
  atimeMs: 1586227933993.0217,
  mtimeMs: 1585882949091.0166,
  ctimeMs: 1586227933995.0222,
  birthtimeMs: 1586227933993.0217,
  atime: 2020-04-07T02:52:13.993Z,
  mtime: 2020-04-03T03:02:29.091Z,
  ctime: 2020-04-07T02:52:13.995Z,
  birthtime: 2020-04-07T02:52:13.993Z
}


  fs模块还提供了fstat()方法,在功能上与stat()等价,只是fstat()方法的第一个参数是文件描述符。在POSIX系统中,文件描述符是一个正整数,它实际上是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当打开或创建一个文件时,就会被分配一个文件描述符。

  在下面的示例中,open()方法的回调函数中包含一个fd参数(即文件描述符),搭配fstat()方法就能读取文件信息。

fs.open('./demo.txt', 'r', (err, fd) => {
  fs.fstat(fd, (err, stats) => {
    console.log(stats);
  });
});

4)监控文件

  fs模块提供了两种方法来监控文件:watch()和watchFile(),前者能监控文件或目录的更改,后者只能监控文件的更改。

  watch()方法的监听器回调包含两个参数,第一个是事件类型(包括rename和change),第二个是触发事件的文件名称,如下所示。

fs.watch('./demo.txt', (eventType, filename) => {
  console.log(eventType, filename);
});

  执行node命令后,每次更改demo.txt文件,就会在控制台打印出下面这条语句。

$ node index.js
change demo.txt

  虽然watch()方法的性能优于watchFile()方法,但是watch()不是一个跨平台的方法,其表现在各个平台中并非百分百一致(例如filename参数不能保证提供),而watchFile()是跨平台的。

5)异步文件

  fs.promises是Node提供的一组备用的异步文件系统方法,它们会返回Promise对象而不是通过回调来处理结果。例如以Promise的方式使用stat()方法,如下所示。

const fsPromises = require('fs').promises;
fsPromises.stat('./demo.txt').then(stats => {
  console.log(stats);
});


二、网络


  Node可以处理的网络协议包括HTTP、TCP、HTTPS等,本节将会重点分析HTTP协议。Node中的http模块基于net、stream、events等模块,提供了一系列的网络传输的底层API,可创建HTTP服务器和客户端,包含重定向、代理、上传数据等功能。

1)HTTP服务器

  通过http.createServer()方法就能创建HTTP服务器,其内部会调用net.Server()方法,返回一个http.Server实例。当服务被创建后,就能通过server.listen()方法监听一个端口。

  在下面的示例中,监听的端口是8000,createServer()的回调函数包含两个参数:req和res,分别表示HTTP的请求和响应,前者是IncomingMessage类(一个可读流)的实例,后者是ServerResponse类(一个可写流)的实例。__dirname是一个全局变量,保存着当前文件所处的路径。


const http = require('http'); 
const fs = require('fs'); 
const server = http.createServer(function (req, res) {
  fs.readFile(__dirname + "/index.html", function (err, data) {
    if (err) {
      res.statusCode = 500;
      res.end(String(err));
    } else {
      res.end(data);
    }
  });
}).listen(8000);


  在回调函数中,可修改或解析响应报文,例如像上面当发生错误时,将状态码改成500。在浏览器中访问http://localhost:8000,就能通过end()方法在页面中输出index.html的文件内容。

  注意,必须调用响应对象的end()方法结束此次响应,如果省略,那么页面将会一直处于加载中,阻塞内容渲染。

  http.Server包含一组事件,例如connection和request,如下所示。前者会在建立新的TCP流时触发,后者会在每次请求服务器时触发。

server.on("connection", function (socket) {
  console.log(connection");
});
server.on("request", function (req, res) {
  console.log('request');
});

2)重定向

  3XX格式的状态码用于重定向,例如在Node中实现302跳转,如下所示。

http.createServer(function (req, res) {
  if(req.url == '/strick') {
    res.writeHead(302, {'Location': 'http://www.pwstrick.com'});
  }
  res.end();
}).listen(8000);

  当浏览器访问http://localhost:8000/strick时,才会执行重定向。writeHead()方法可一次性设置响应的状态码和所有的首部。如果只想设置单个响应首部,可以使用setHeader()方法。

3)上传数据

  在实际的业务开发中,免不了上传数据的需求,例如表单提交、图像上传等。下面是一张form表单,包含一个文本框和一个提交按钮。

<form action="http://localhost:8000" method="post">
  <input type="text" name="name" />
  <button type="submit">提交</button>
</form>

  点击提交按钮,会将整张表单提交到HTTP服务器(代码如下所示),假设文本框中输入的内容为“咖啡机strick”。


const http = require('http');
const querystring = require('querystring');
const server = http.createServer(function (req, res) {
  //声明Content-Type响应首部,以免中文乱码
  res.setHeader("Content-Type", "application/json; charset=utf-8");
  const arr = [];
  req.on("data", chunk => {
    arr.push(chunk);
  });
  req.on("end", () => {
    const buf = Buffer.concat(arr);        //拼接Buffer数据
    const params = querystring.decode(buf.toString());
    console.log(params.name);             //"咖啡机strick"
    res.write(JSON.stringify(params));    //响应数据
    res.end();
  });
}).listen(8000);


  在data事件中接收数据并添加到arr数组中,然后在end事件中由Buffer.concat()方法拼接Buffer数据。querystring模块的decode()方法可将查询字符串解析成一个对象。write()方法会将响应数据发送给客户端。

4)客户端服务

  http模块提供了request()方法,可让客户端向服务器发起请求。在下面的示例中,postData变量是要发送的数据,options变量是各种配置参数,包括请求首部的信息。


const http = require('http'); 
const querystring = require('querystring');
const postData = querystring.stringify({
  'name': '咖啡机strick'
});
const options = {
  hostname: 'localhost',
  port: 8000,
  path: '/',
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Content-Length': Buffer.byteLength(postData)
  }
};
const req = http.request(options, (res) => {
  const code = res.statusCode;                    //状态码
  const headers = JSON.stringify(res.headers);       //响应首部
  res.setEncoding('utf8');         //为可读流设置字符编码
  res.on('data', (chunk) => {
    console.log(chunk);            //响应数据
  });
  res.on('end', () => {
    console.log('响应中已无数据');
  });
});
req.write(postData);
req.end();


  注意,在请求最后需要调用end()方法,结束本次请求。Node还提供了一个基于request()的便捷方法:get(),它会自动调用req.end()方法,并且请求方法是GET。

5)代理

  代理是一种特殊的网络服务,允许一个客户端通过这个服务与目标服务器进行间接的连接,也就是在它们之间建立了一层中转,可用来过滤广告、控制内部资源的访问权限、保障终端的隐私或安全等。

  http模块可搭建出一个简易的HTTP代理服务器,下面示例引用自《Node.js硬实战》技巧52一节。


const http = require('http');
const url = require('url');
http.createServer(function (req, res) {
  const options = url.parse(req.url);  //一个URL对象
  options.headers = req.headers;
  req.on('data', chunk => {            //将请求的原始数据发送给代理
    proxyRequest.write(chunk);
  });
  req.on('end', chunk => {             //完成原始请求
    proxyRequest.end();
  });
  //复制原始请求
  const proxyRequest = http.request(options, proxyResponse => {
    proxyResponse.on('data', chunk => {    //将响应的原始数据发送给客户端
      res.write(chunk);
    });
    proxyResponse.on('end', chunk => {     //完成代理请求
      res.end();
    });
    //将响应报文发送给客户端
    res.writeHead(proxyResponse.statusCode, proxyResponse.headers);
  });
}).listen(8000);

  url模块的parse()方法能将字符串转换成一个URL对象。在绑定请求对象的data事件后,就能将客户端的请求数据发送给代理。通过http.request()方法发起一次代理请求,并将服务器的响应数据发送给客户端。


相关文章
|
4月前
|
存储 安全 Unix
网络文件系统 (NFS)
【10月更文挑战第12天】
205 5
|
4月前
|
存储 缓存 安全
网络文件系统 (NFS)
【10月更文挑战第11天】
76 1
|
1月前
|
Ubuntu Linux 开发者
Ubuntu20.04搭建嵌入式linux网络加载内核、设备树和根文件系统
使用上述U-Boot命令配置并启动嵌入式设备。如果配置正确,设备将通过TFTP加载内核和设备树,并通过NFS挂载根文件系统。
97 15
|
1月前
|
存储 监控 算法
局域网网络管控里 Node.js 红黑树算法的绝妙运用
在数字化办公中,局域网网络管控至关重要。红黑树作为一种自平衡二叉搜索树,凭借其高效的数据管理和平衡机制,在局域网设备状态管理中大放异彩。通过Node.js实现红黑树算法,可快速插入、查找和更新设备信息(如IP地址、带宽等),确保网络管理员实时监控和优化网络资源,提升局域网的稳定性和安全性。未来,随着技术融合,红黑树将在网络管控中持续进化,助力构建高效、安全的局域网络生态。
50 9
|
6月前
|
存储 安全 JavaScript
云计算浪潮中的网络安全之舵探索Node.js中的异步编程模式
【8月更文挑战第27天】在数字化时代的风帆下,云计算如同一片广阔的海洋,承载着企业与个人的数据梦想。然而,这片海洋并非总是风平浪静。随着网络攻击的波涛汹涌,如何确保航行的安全成为了每一个船员必须面对的挑战。本文将探索云计算环境下的网络安全策略,从云服务的本质出发,深入信息安全的核心,揭示如何在云海中找到安全的灯塔。
|
2月前
|
Ubuntu Unix Linux
Linux网络文件系统NFS:配置与管理指南
NFS 是 Linux 系统中常用的网络文件系统协议,通过配置和管理 NFS,可以实现跨网络的文件共享。本文详细介绍了 NFS 的安装、配置、管理和常见问题的解决方法,希望对您的工作有所帮助。通过正确配置和优化 NFS,可以显著提高文件共享的效率和安全性。
241 7
|
6月前
|
JavaScript 算法 前端开发
采招网JS逆向:基于AES解密网络数据
采招网JS逆向:基于AES解密网络数据
110 0
|
3月前
|
存储 网络协议 安全
软件管理,磁盘存储,文件系统以及网络协议
【11月更文挑战第9天】本文介绍了软件管理、磁盘存储和网络协议等内容。软件管理包括软件生命周期管理和软件包管理,涉及需求分析、设计、实现、测试、发布、维护等阶段,以及软件包的安装、升级和依赖关系处理。磁盘存储部分讲解了磁盘的物理结构、分区与格式化、存储管理技术(如 RAID 和存储虚拟化)。网络协议部分涵盖了分层模型、重要协议(如 HTTP、TCP、IP)及其应用与安全。
|
3月前
|
机器学习/深度学习 自然语言处理 前端开发
前端神经网络入门:Brain.js - 详细介绍和对比不同的实现 - CNN、RNN、DNN、FFNN -无需准备环境打开浏览器即可测试运行-支持WebGPU加速
本文介绍了如何使用 JavaScript 神经网络库 **Brain.js** 实现不同类型的神经网络,包括前馈神经网络(FFNN)、深度神经网络(DNN)和循环神经网络(RNN)。通过简单的示例和代码,帮助前端开发者快速入门并理解神经网络的基本概念。文章还对比了各类神经网络的特点和适用场景,并简要介绍了卷积神经网络(CNN)的替代方案。
599 1
|
4月前
|
JavaScript Unix API
Node.js 文件系统
10月更文挑战第6天
36 2

热门文章

最新文章

  • 1
    当面试官再问我JS闭包时,我能答出来的都在这里了。
    40
  • 2
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    26
  • 3
    Node.js 中实现多任务下载的并发控制策略
    32
  • 4
    【2025优雅草开源计划进行中01】-针对web前端开发初学者使用-优雅草科技官网-纯静态页面html+css+JavaScript可直接下载使用-开源-首页为优雅草吴银满工程师原创-优雅草卓伊凡发布
    25
  • 5
    【JavaScript】深入理解 let、var 和 const
    49
  • 6
    【04】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架二次开发准备工作-以及建立初步后端目录菜单列-优雅草卓伊凡商业项目实战
    46
  • 7
    【03】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架搭建-服务端-后台管理-整体搭建-优雅草卓伊凡商业项目实战
    54
  • 8
    【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
    57
  • 9
    如何通过pm2以cluster模式多进程部署next.js(包括docker下的部署)
    72
  • 10
    【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
    55