NodeJS学习笔记之FS文件模块


Posted in NodeJs onJanuary 13, 2015

一,开篇分析

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

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

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

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

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

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

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

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

 var fs = require("fs") ;

 fs.readFile("bb.txt","utf8",function (error,data){

     if(error) throw error ;

     console.log(data) ;

 }) ;

运行结果:

NodeJS学习笔记之FS文件模块

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

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

NodeJS学习笔记之FS文件模块

再来一个写操作,如下:

 var fs = require("fs") ;

 var txt = "大家要好好学习NodeJS啊!!!" ;

 //写入文件

 fs.writeFile("bb.txt",txt,function (err) {

     if (err) throw err ;

     console.log("File Saved !"); //文件被保存

 }) ;

运行结果:

NodeJS学习笔记之FS文件模块

在列举一些常用的实例:

// 删除文件

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”

 <html>

     <head>

         <style type="text/css">

             div {

                 margin-top: 50px;

                
 width: 100%; 

                    margin: 0px;

                 
height:120px;

                 
line-height:120px;

                    color:#fff;

                    font-size:22px;

                    background:#ff9900;

                   text-align: center;

             }

         </style>

     </head>

     <body>

         <div>Hello,大熊!</div>

     </body>

 </html>

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

 var http = require('http') ;

 var fs = require("fs") ;

 var server = http.createServer(function(req,res){

     fs.readFile("bb.html","utf-8", function(err, data){

       if(err) {

           res.writeHead(500, {'Context-Type': 'text/plain'});

           res.end('specify file not exists! or server error!');

       }

       else{

         res.writeHead(200, {'Context-Type': 'text/html'});

         res.write(data);

         res.end();

       }

   })

 }) ;

 server.listen(8888) ;

 console.log("http server running on port 8888 ...") ;

以下是运行结果:

NodeJS学习笔记之FS文件模块

现在我们需要思考一下,如果我们要发送的不是一个单纯的文本文件而是超媒体文件比如说 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”

 var http = require('http');

 var url = require('url');

 function start(route, handler) {

     function onRequest (request, response) {

         var pathname = url.parse(request.url).pathname;

         // 路由到相应的业务逻辑

         route (pathname, handler, response, request);

     }

     http.createServer(onRequest).listen(3000);

     console.log('server is starting');

 }

 exports.start = start;

(2),建立“route.js”

 function route (pathname, handler, response, request) {

     console.log('about to route a request for ' + pathname);

     if (typeof handler[pathname] === 'function') {

         return handler[pathname](response, request);

     } else {

         console.log('no request handler found for ' + pathname);

         response.writeHead(404, {'Content-Type': 'text/html'});

         response.write('404 Not Found!');

         response.end();

     }

 }

 exports.route = route;

(3),建立“requestHandler.js”

var querystring = require('querystring'),

    fs = require('fs'),

    formidable = require('formidable');

function start (response, request) {

    console.log('start module');

  var body = '<html>'+

      '<head>'+

      '<meta http-equiv="Content-Type" '+

      'content="text/html; charset=UTF-8" />'+

      '</head>'+

      '<body>'+

      '<form action="/upload" enctype="multipart/form-data" method="post">'+

      '<input type="file" name="upload" multiple="multiple">'+

      '<input type="submit" value="Submit text" />'+

      '</form>'+

      '</body>'+

      '</html>';

    response.writeHead(200, {'Content-Type': 'text/html'});

    response.write(body);

    response.end();

}

function upload (response, request) {

    console.log('upload module');

    var form = new formidable.IncomingForm();

    form.parse(request, function (error, fields, files) {

        fs.renameSync(files.upload.path, '/tmp/test.png');

        response.writeHead(200, {'Content-Type': 'text/html'});

        response.write('You\'ve sent: <br />');

        response.write('<img src="/show" />');

        response.end();

    });

}

function show (response, request) {

    console.log('show module');

    fs.readFile ('/tmp/test.png', 'binary', function (error, file) {

        if (error) {

            response.writeHead(200, {'Content-Type': 'text/html'});

            response.write(error);

            response.end();

        } else {

            response.writeHead(200, {'Content-Type': 'image/png'});

            response.write(file, 'binary');

            response.end();

        }

    });

}

exports.start = start;

exports.upload = upload;

exports.show= show;

(4),建立“index.js”

 var server = require('./server');

 var router = require('./router');

 var requestHandler = require('./requestHandler');

 var formidable = require('formidable'); // require路径搜索算法??

 var handler = {};

 handler['/'] = requestHandler.start;

 handler['/start'] = requestHandler.start;

 handler['/upload'] = requestHandler.upload;

 handler['/show'] = requestHandler.show;

 server.start(router.route, handler);

四,总结一下

(1),理解 "Fs与Stream之间的联系" 。
(2),熟练使用 "FS" 相关的api。
(3),注意细节的把控,比如: 文件操作api同步方式与异步方式之间的处理细节。
(4),最后强调:理解文件上传例子中的代码组织方式,不断重构,不断总结。

NodeJs 相关文章推荐
使用Nodejs开发微信公众号后台服务实例
Sep 03 NodeJs
详解NodeJs支付宝移动支付签名及验签
Jan 06 NodeJs
Nodejs 获取时间加手机标识的32位标识实现代码
Mar 07 NodeJs
详解NodeJS框架express的路径映射(路由)功能及控制
Mar 24 NodeJs
nodejs获取微信小程序带参数二维码实现代码
Apr 12 NodeJs
详解HTTPS 的原理和 NodeJS 的实现
Jul 04 NodeJs
nodejs创建简易web服务器与文件读写的实例
Sep 07 NodeJs
NodeJS简单实现WebSocket功能示例
Feb 10 NodeJs
nodejs简单读写excel内容的方法示例
Mar 16 NodeJs
Nodejs使用Mongodb存储与提供后端CRD服务详解
Sep 04 NodeJs
Nodejs实现的操作MongoDB数据库功能完整示例
Feb 02 NodeJs
Nodejs对postgresql基本操作的封装方法
Feb 20 NodeJs
NodeJS学习笔记之Http模块
Jan 13 #NodeJs
Nodejs学习笔记之Stream模块
Jan 13 #NodeJs
Nodejs学习笔记之NET模块
Jan 13 #NodeJs
Nodejs学习笔记之Global Objects全局对象
Jan 13 #NodeJs
Nodejs为什么选择javascript为载体语言
Jan 13 #NodeJs
NodeJS中Buffer模块详解
Jan 07 #NodeJs
Nodejs中读取中文文件编码问题、发送邮件和定时任务实例
Jan 01 #NodeJs
You might like
解析PHP缓存函数的使用说明
2013/05/10 PHP
PHP程序员基本要求和必备技能
2014/05/09 PHP
ThinkPHP结合AjaxFileUploader实现无刷新文件上传的方法
2014/10/29 PHP
PHP手机短信验证码实现流程详解
2018/05/17 PHP
javascript之dhDataGrid Ver2.0.0代码
2007/07/01 Javascript
jQuery的运行机制和设计理念分析
2011/04/05 Javascript
JavaScript中的稀疏数组与密集数组[译]
2012/09/17 Javascript
js判断鼠标同时离开两个div的思路及代码
2013/05/31 Javascript
javascript截取字符串(通过substring实现并支持中英文混合)
2013/06/24 Javascript
JS图片自动轮换效果实现思路附截图
2014/04/30 Javascript
JavaScript中的闭包(Closure)详细介绍
2014/12/30 Javascript
详解AngularJS实现表单验证
2015/12/10 Javascript
深入理解jquery跨域请求方法
2016/05/18 Javascript
JavaScript仿百度图片浏览效果
2016/11/23 Javascript
jQuery 如何实现一个滑动按钮开关
2016/12/01 Javascript
javascript实现非常简单的小数取整功能示例
2017/06/13 Javascript
浅谈Vue.js中ref ($refs)用法举例总结
2017/12/19 Javascript
web前端页面生成exe可执行文件的方法
2018/02/08 Javascript
jQuery+CSS实现的标签页效果示例【测试可用】
2018/08/14 jQuery
Angular7.2.7路由使用初体验
2019/03/01 Javascript
vue项目移动端实现ip输入框问题
2019/03/19 Javascript
关于layui 下拉列表的change事件详解
2019/09/20 Javascript
vue循环数组改变点击文字的颜色
2019/10/14 Javascript
在Django中创建动态视图的教程
2015/07/15 Python
Python中字符串的常见操作技巧总结
2016/07/28 Python
pandas groupby 分组取每组的前几行记录方法
2018/04/20 Python
解决tensorflow 释放图,删除变量问题
2020/06/23 Python
Pandas DataFrame求差集的示例代码
2020/12/13 Python
荷兰电脑专场:Paradigit
2018/05/05 全球购物
领先的荷兰线上超市:荷兰之家Holland at Home(支持中文)
2021/01/21 全球购物
酒店应聘自荐信
2013/11/09 职场文书
初中生学习生活的自我评价
2013/11/20 职场文书
青春寄语大全
2014/04/09 职场文书
党的群众路线教育实践活动总结大会主持词
2014/10/30 职场文书
2015年乡镇流动人口工作总结
2015/05/12 职场文书
MySQL定时备份数据库(全库备份)的实现
2021/09/25 MySQL