大熊君大话NodeJS之------FS文件模块
一,开篇分析
文件系统模块是一个简单包装的标准 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) ;
}) ;
运行结果:
这里要注意的是:读取文件一定要设置编码,否则默认是 ”buffer“ 形式出现。
再看没设置的运行效果,区别还是很明显的。如下:
再来一个写操作,如下:
var fs = require("fs") ;
var txt = "大家要好好学习NodeJS啊!!!" ;
//写入文件
fs.writeFile("bb.txt",txt,function (err) {
if (err) throw err ;
console.log("File Saved !"); //文件被保存
}) ;
运行结果:
在列举一些常用的实例:
// 删除文件
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 ...") ;
以下是运行结果:
现在我们需要思考一下,如果我们要发送的不是一个单纯的文本文件而是超媒体文件比如说 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之------FS文件模块的更多相关文章
- 大熊君大话NodeJS之------Connect中间件模块(第一季)
一,开篇分析 截止到今天来说,NodeJS系列文章已经有将近十篇了,让我们回顾一下: (1),大熊君大话NodeJS之开篇------Why NodeJS(将Javascript进行到底) (2),大 ...
- 大熊君大话NodeJS之------Net模块
一,开篇分析 从今天开始,我们来深入具体的模块学习,这篇文章是这个系列(大熊君大话NodeJS)文章的第三篇,前两篇主要是以理论为主,相信大家在前两篇的学习中, 对NodeJS也有一个基本的认识,没事 ...
- 大熊君大话NodeJS之 ------ Connect中间件第二季(源码分析)
一,开篇分析 大家好,大熊君又回来了,今天这篇文章主要是对"Connect"中间件以及相关辅助中间件,做一个源码分析系列,我想上一篇文章大家也看了, 介绍了使用方式及用途,而这篇也 ...
- 大熊君大话NodeJS之开篇------Why NodeJS(将Javascript进行到底)
一,开篇分析 大家好啊,大熊君又来啦(*^__^*) 嘻嘻……,之前我写过一系列关于JS(OOP与设计模式)方面的文章,反响还好,其实这也是对我本人最大的鼓励,于是我决定我要将JavaScript进行 ...
- 大熊君大话NodeJS之------基于Connect中间件的小应用(Bigbear记事本应用之第一篇)
一,开篇分析 大家好哦,大熊君又来了,昨天因为有点个人的事没有写博客,今天又出来了一篇,这篇主要是写一个记事本的小应用,前面的文章, 我也介绍过“Connect”中间件的使用以及“Mongodb”的用 ...
- 大熊君大话NodeJS之------Global Objects全局对象
一,开篇分析 在上个章节中我们学习了NodeJS的基础理论知识,对于这些理论知识来说理解是至关重要的,在后续的章节中,我们会对照着官方文档逐步学习里面的各部分模块,好了该是本文主角登台亮相的时候了,G ...
- 大熊君大话NodeJS之------Stream模块
一,开篇分析 流是一个抽象接口,被 Node 中的很多对象所实现.比如对一个 HTTP 服务器的请求是一个流,stdout 也是一个流.流是可读,可写或兼具两者的. 最早接触Stream是从早期的un ...
- 大熊君大话NodeJS之------(Url,QueryString,Path)模块
一,开篇分析 这篇文章把这三个模块拿来一起说,原因是它们各自的篇幅都不是很长,其次是它们之间存在着依赖关系,所以依次介绍并且实例分析.废话不多说了,请看下面文档: (1),"Url模块&qu ...
- 大熊君大话NodeJS之------Http模块
一,开篇分析 首先“Http”这个概念大家应该比较熟悉了,它不是基于特定语言的,是一个通用的应用层协议,不同语言有不同的实现细节,但是万变不离其宗,思想是相同的, NodeJS作为一个宿主运行环境,以 ...
随机推荐
- 【poj3615】 Cow Hurdles
http://poj.org/problem?id=3615 (题目链接) 题意 给出一张有向图,求从u到v最大边最小的路径的最大边.→_→不会说话了.. Solution 好久没写Floyd了,水一 ...
- Ajax请求接口加密研究(针对网页前端的接口安全加密机制研究)
通常我们在h5前端调用后台接口时,一般是ajax,那么接口的安全成了一个问题. 这里可以肯定的说,前端调用的接口一定要验证! 然后剖析了微信网页版.京东网页版这些,也都是通过接口的形势绑定数据,所以在 ...
- Linux内核邮件列表发送和回复格式研究
1.使用的内容格式为[纯文本],这个在国内的客户端已经没有了,大公司只有微软的outlook. 2.回复引用时,使用符号[>]作为标记,且回复的内容不能在最顶部,应该在最下面.参考:http:/ ...
- squid日志时间转换
squid日志时间是unix时间戳 不利于观看 python脚本进行转换 #!/usr/bin/env python #2014-6-5 pdd import re import time impor ...
- Google Guava vs Apache Commons for Argument Validation
It is an established good practice to validate method arguments at the beginning of the method body. ...
- K-D Tree
这篇随笔是对Wikipedia上k-d tree词条的摘录, 我认为解释得相当生动详细, 是一篇不可多得的好文. Overview A \(k\)-d tree (short for \(k\)-di ...
- 【项目】'NSRangeException', reason: '*** -[__NSArrayM removeObjectAtIndex:]: index 2 beyond bounds [0 .. 1]'
问题代码: [self.assetsArray objectAtIndex:indexPath.row] 问题解决思路:这里
- Rabbitmq -Routeing模式- python编码实现
(using the pika 0.10.0 Python client) In the previous tutorial we built a simple logging system. We ...
- Codeforces Round #345 D. Image Preview(二分)
题目链接 题意:看一个图片需要1单位时间,如果是 w 需要翻转 b 时间,切换到相邻位置(往左或者往右)需要 a 时间,求T时间最多能看几张图片 从第一个开始向右走看若干个图片然后往如果往左走就不会再 ...
- POJ3114 Countries in War (强连通分量 + 缩点 + 最短路径 + 好题)
题目链接 题意是说在几个邮局之间传送一份信件,如果出发点和终止点在同一个国家传递,则时间为0,否则让你求花费最少时间,如果不能传到,则输出Nao e possivel entregar a carta ...