大熊君大话NodeJS之------FS文件模块

一,开篇分析

文件系统模块是一个简单包装的标准 POSIX 文件 I/O 操作方法集。可以通过调用 require("fs") 来获取该模块。文件系统模块中的所有方法均有异步和同步版本。

(1),文件系统模块中的异步方法需要一个完成时的回调函数作为最后一个传入形参。

(2),回调函数的构成由调用的异步方法所决定,通常情况下回调函数的第一个形参为返回的错误信息。

(3),如果异步操作执行正确并返回,该错误形参则为null或者undefined如果使用的是同步版本的操作方法,一旦出现错误,会以通常的抛出错误的形式返回错误。

(4),可以用trycatch等语句来拦截错误并使程序继续进行。

我们先看一个简单的例子,读取文件("bb.txt"):

(1),建立文件"bb.txt“,如下内容(”大家好,我是大雄君!(*^__^*) 嘻嘻……“)。

(2),读取文件操作如下代码:

1 var fs = require("fs") ;
2 fs.readFile("bb.txt","utf8",function (error,data){
3     if(error) throw error ;
4     console.log(data) ;
5 }) ;

运行结果:

这里要注意的是:读取文件一定要设置编码,否则默认是 ”buffer“ 形式出现。

再看没设置的运行效果,区别还是很明显的。如下:

再来一个写操作,如下:

1 var fs = require("fs") ;
2 var txt = "大家要好好学习NodeJS啊!!!" ;
3 //写入文件
4 fs.writeFile("bb.txt",txt,function (err) {
5     if (err) throw err ;
6     console.log("File Saved !"); //文件被保存
7 }) ;

运行结果:

在列举一些常用的实例:

// 删除文件
fs.unlink(‘bb.txt‘, function(){
 console.log(‘success‘) ;
}) ;

// 修改文件名称
fs.rename(‘bb.txt‘,‘bigbear.txt‘,function(err){
 console.log(‘rename success‘) ;
});

 // 查看文件状态
fs.stat(‘bb.txt‘, function(err, stat){
  console.log(stat);
});

// 判断文件是否存在
fs.exists(‘bb.txt‘, function( exists ){
    console.log( exists ) ;
}) ;

二,Fs与Stream之间的联系

"Stream" 具有异步的特性。我么可以将一个文件或一段内容分为未知个制定大小的 "chunk" 去读取,每读取到一个 "chunk" 我们就将他输出。直到文件读完。这就像 "http1.1" 种支持的 "Transfer-Encoding: chunked" 那样。 ("chunk"可以以任何的形式存在,NodeJS默认是以 "Buffer" 的形式存在,这样更高效)。NodeJS中的"Stream"具备Unix系统上的一个超级特性就是 ("pipe" ------ 管道)。

还记得 “Http模块那篇” 第一个NodeJS程序, "Hello,大熊!" 吗?我们基于那个小程序做一下修改,如下代码:

(1),建立“bb.html”

 1 <html>
 2     <head>
 3         <style type="text/css">
 4             div {
 5                   margin-top: 50px;
 6                   width: 100%;
 7                    margin: 0px;
 8                   height:120px;
 9                   line-height:120px;
10                    color:#fff;
11                    font-size:22px;
12                    background:#ff9900;
13                   text-align: center;
14             }
15         </style>
16     </head>
17     <body>
18         <div>Hello,大熊!</div>
19     </body>
20 </html>

(2),修改之前的程序如下:

 1 var http = require(‘http‘) ;
 2 var fs = require("fs") ;
 3 var server = http.createServer(function(req,res){
 4     fs.readFile("bb.html","utf-8", function(err, data){
 5       if(err) {
 6           res.writeHead(500, {‘Context-Type‘: ‘text/plain‘});
 7           res.end(‘specify file not exists! or server error!‘);
 8       }
 9       else{
10         res.writeHead(200, {‘Context-Type‘: ‘text/html‘});
11         res.write(data);
12         res.end();
13       }
14   })
15 }) ;
16 server.listen(8888) ;
17 console.log("http server running on port 8888 ...") ;

以下是运行结果:

现在我们需要思考一下,如果我们要发送的不是一个单纯的文本文件而是超媒体文件比如说 Google 2014 IO 大会 的全程高清视频文件。mp4 格式。长度2个多小时1080p。

大概4个多GB。已知 "readFile" 的工作方式是将文件读取到内存。那么这么大一个文件显然是不能这么做的。那该怎么办呢?是之后就需要使用 stream 的来做。那么是这样的。

代码如下像这样:

fs.createReadStream(__dirname + ‘/vedio.mp4‘).pipe(res) ;

总结一下:

这些代码可以实现需要的功能,但是服务在发送文件数据之前需要缓存整个文件数据到内存,如果"bb.html"文件很 
大并且并发量很大的话,会浪费很多内存。因为用户需要等到整个文件缓存到内存才能接受的文件数据,这样导致 
用户体验相当不好。不过还好 "(req, res)" 两个参数都是Stream,这样我们可以用fs.createReadStream()代替"fs.readFile()"。

三,实例赏心

来一个文件上传的小栗子:

(1),建立“server.js”

 1 var http = require(‘http‘);
 2 var url = require(‘url‘);
 3 function start(route, handler) {
 4     function onRequest (request, response) {
 5         var pathname = url.parse(request.url).pathname;
 6         // 路由到相应的业务逻辑
 7         route (pathname, handler, response, request);
 8     }
 9     http.createServer(onRequest).listen(3000);
10     console.log(‘server is starting‘);
11 }
12 exports.start = start;

(2),建立“route.js”

 1 function route (pathname, handler, response, request) {
 2     console.log(‘about to route a request for ‘ + pathname);
 3     if (typeof handler[pathname] === ‘function‘) {
 4         return handler[pathname](response, request);
 5     } else {
 6         console.log(‘no request handler found for ‘ + pathname);
 7         response.writeHead(404, {‘Content-Type‘: ‘text/html‘});
 8         response.write(‘404 Not Found!‘);
 9         response.end();
10     }
11 }
12 exports.route = route;

(3),建立“requestHandler.js”

 1 var querystring = require(‘querystring‘),
 2     fs = require(‘fs‘),
 3     formidable = require(‘formidable‘);
 4
 5 function start (response, request) {
 6     console.log(‘start module‘);
 7
 8   var body = ‘<html>‘+
 9       ‘<head>‘+
10       ‘<meta http-equiv="Content-Type" ‘+
11       ‘content="text/html; charset=UTF-8" />‘+
12       ‘</head>‘+
13       ‘<body>‘+
14       ‘<form action="/upload" enctype="multipart/form-data" method="post">‘+
15       ‘<input type="file" name="upload" multiple="multiple">‘+
16       ‘<input type="submit" value="Submit text" />‘+
17       ‘</form>‘+
18       ‘</body>‘+
19       ‘</html>‘;
20
21     response.writeHead(200, {‘Content-Type‘: ‘text/html‘});
22     response.write(body);
23     response.end();
24 }
25
26 function upload (response, request) {
27     console.log(‘upload module‘);
28     var form = new formidable.IncomingForm();
29     form.parse(request, function (error, fields, files) {
30         fs.renameSync(files.upload.path, ‘/tmp/test.png‘);
31         response.writeHead(200, {‘Content-Type‘: ‘text/html‘});
32         response.write(‘You\‘ve sent: <br />‘);
33         response.write(‘<img src="/show" />‘);
34         response.end();
35     });
36 }
37
38 function show (response, request) {
39     console.log(‘show module‘);
40     fs.readFile (‘/tmp/test.png‘, ‘binary‘, function (error, file) {
41         if (error) {
42             response.writeHead(200, {‘Content-Type‘: ‘text/html‘});
43             response.write(error);
44             response.end();
45         } else {
46             response.writeHead(200, {‘Content-Type‘: ‘image/png‘});
47             response.write(file, ‘binary‘);
48             response.end();
49
50         }
51     });
52 }
53
54 exports.start = start;
55 exports.upload = upload;
56 exports.show= show;

(4),建立“index.js”

 1 var server = require(‘./server‘);
 2 var router = require(‘./router‘);
 3 var requestHandler = require(‘./requestHandler‘);
 4 var formidable = require(‘formidable‘); // require路径搜索算法??
 5 var handler = {};
 6 handler[‘/‘] = requestHandler.start;
 7 handler[‘/start‘] = requestHandler.start;
 8 handler[‘/upload‘] = requestHandler.upload;
 9 handler[‘/show‘] = requestHandler.show;
10 server.start(router.route, handler);

四,总结一下

(1),理解 "Fs与Stream之间的联系" 。

 

(2),熟练使用 "FS" 相关的api。

 

(3),注意细节的把控,比如: 文件操作api同步方式与异步方式之间的处理细节。

 

(4),最后强调:理解文件上传例子中的代码组织方式,不断重构,不断总结。

            哈哈哈,本篇结束,未完待续,希望和大家多多交流够沟通,共同进步。。。。。。呼呼呼……(*^__^*)             

时间: 2024-10-05 06:01:48

大熊君大话NodeJS之------FS文件模块的相关文章

大熊君大话NodeJS之------Net模块

一,开篇分析 从今天开始,我们来深入具体的模块学习,这篇文章是这个系列(大熊君大话NodeJS)文章的第三篇,前两篇主要是以理论为主,相信大家在前两篇的学习中, 对NodeJS也有一个基本的认识,没事!!!趁热打铁,让我们继续将NodeJS进行到底,好了废话不多说,直接进入今天的主题 “Net模块” ,那么”Net“应该如何理解那? 它是做什么用的那?(Net模块可用于创建Socket服务器或Socket客户端. NodeJS 的数据通信,最基础的两个模块是 Net 和 Http,前者是基于 T

大熊君大话NodeJS之开篇------Why NodeJS(将Javascript进行到底)

一,开篇分析 大家好啊,大熊君又来啦(*^__^*) 嘻嘻……,之前我写过一系列关于JS(OOP与设计模式)方面的文章,反响还好,其实这也是对我本人最大的鼓励,于是我决定我要将JavaScript进行到底 准备写一个NodeJS方面的系列文章,由浅入深,循序渐进,秉承的理念是重思想,多实践,勤能补拙,贵在坚持. 我们先来看看NodeJS官网上的介绍: 其特点为: 1,它是一个Javascript运行环境 2,依赖于Chrome V8引擎进行代码解释 3,事件驱动 4, 非阻塞I/O 5, 轻量.

大熊君大话NodeJS之------基于Connect中间件的小应用(Bigbear记事本应用之第一篇)

一,开篇分析 大家好哦,大熊君又来了,昨天因为有点个人的事没有写博客,今天又出来了一篇,这篇主要是写一个记事本的小应用,前面的文章, 我也介绍过“Connect”中间件的使用以及“Mongodb”的用法,今天就结合这两个中间件,写个实际的例子,不断完善和重构,已达到 充分学习的目的.好了,废话不说了,直接进入主题. 二,需求分析 (1),用户注册,登录功能(没有涉及很复杂的交互场景,注册时会有用户判断是否已存在). (2),用户登录成功,进入笔记管理系统的后台(笔记模块的增删改查功能). (3)

大熊君大话NodeJS之------Global Objects全局对象

一,开篇分析 在上个章节中我们学习了NodeJS的基础理论知识,对于这些理论知识来说理解是至关重要的,在后续的章节中,我们会对照着官方文档逐步学习里面的各部分模块,好了该是本文主角登台亮相的时候了,Global  让我们来看一下官方的定义: Global Objects全局对象 These objects are available in all modules. Some of these objects aren't actually in the global scope but in t

大熊君大话NodeJS之------Stream模块

一,开篇分析 流是一个抽象接口,被 Node 中的很多对象所实现.比如对一个 HTTP 服务器的请求是一个流,stdout 也是一个流.流是可读,可写或兼具两者的. 最早接触Stream是从早期的unix开始的, 数十年的实践证明Stream 思想可以很简单的开发出一些庞大的系统. 在unix里,Stream是通过 "|" 实现的.在node中,作为内置的stream模块,很多核心模块和三方模块都使用到. 和unix一样,node stream主要的操作也是.pipe(),使用者可以使

大熊君大话NodeJS之------Http模块

一,开篇分析 首先“Http”这个概念大家应该比较熟悉了,它不是基于特定语言的,是一个通用的应用层协议,不同语言有不同的实现细节,但是万变不离其宗,思想是相同的, NodeJS作为一个宿主运行环境,以JavaScript为宿主语言,它也有自己实现的一套标准,这篇文章我们就一起来学习一下 “Http模块” .但是作为前提来说, 希望大家可以先阅读一下官网提供的api,有一个前置了解,这样就方便多了,以下是Http部分的api概览: HTTP http.STATUS_CODES http.creat

大熊君大话NodeJS之------(Url,QueryString,Path)模块

一,开篇分析 这篇文章把这三个模块拿来一起说,原因是它们各自的篇幅都不是很长,其次是它们之间存在着依赖关系,所以依次介绍并且实例分析.废话不多说了,请看下面文档: (1),"Url模块" 来个小栗子: 1 var url = require('url'); 2 var queryUrl = "http://localhost:8888/bb?name=bigbear&memo=helloworld" ; 3 console.log(typeof url.pa

大熊君大话NodeJS之------MongoDB模块(额外篇)

一,开篇分析 这篇属于扩展知识篇,因为在下面的文章中会用到数据库操作,所以今天就来说说它(Mongodb模块). (1),简介 MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. MongoDB是一个高性能,开源,无模式的文档型数据库,是当前NoSql数据库中比较热门的一种. MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的.他支持的数据结构非常松散,是类似json的bj

大熊君大话NodeJS之------Buffer模块

一,开篇分析 所谓缓冲区Buffer,就是 "临时存贮区" 的意思,是暂时存放输入输出数据的一段内存. JS语言自身只有字符串数据类型,没有二进制数据类型,因此NodeJS提供了一个与String对等的全局构造函数Buffer来提供对二进制数据的操作.除了可以读取文件得到Buffer的实例外,还能够直接构造,例如: var buffer = new Buffer([ 0x68, 0x65, 0x6c, 0x6c, 0x6f ]) ; Buffer与字符串类似,除了可以用.length属