通过上一篇文章“NodeJS服务器:一行代码 = 一个的HTTP服务器”,我们已经开启了NodeJS之旅,开发了一个监听在8000端口的HTTP服务器,虽然功能很简单,但是,已经让我们感受到用NodeJS开发服务器是一件简单、愉快的事情。现在,我们按着既定的目标----将电脑里的文件共享给手机,继续前进。

老规矩,先上一个图:

回到我们的项目目标,要实现的功能是:当有客户端向NodeJS服务器发送请求的时候,就读取电脑D:\下面的

ilinkit_logo.png的图片文件作为响应,反馈给客户端,代码如下:

 var http = require( 'http' );
var fs = require('fs'); var file_path = "D:\\ilinkit_logo.png" ;
var file_stream; var server =http.createServer( function ( request ,response ){
file_stream = fs.createReadStream( file_path );
file_stream.on( 'data' , function( chunk ){
response.write( chunk );
} );
file_stream.on( 'end' , function( ){
response.end( "" );
console.log( "文件读取完毕" );
} );
file_stream.on('error', function(err){
response.end( "文件读取失败!" );
});
} );
server.listen( 8000 );
console.log( 'HTTP服务器启动中,端口:8000.....' );

这个代码也比较简单,下面对关键的代码行说明如下:

第2行:加载fs模块,因为我们要用它来读取电脑中的本地文件。

第8行:当有客户端有发送请求时,用fs读取文件到文件流之中。

文件流的概念,和Java、C++中文件流的概念类似,相当于建立了一个管道,这个我们待会儿在优化版本中会再次体会到。

第9行、第12行、第16行:分别实现在文件读取过程中,有数据读取到时(data)、数据读取结束(end)和读取数据发生错误时(error)的响应函数。

第10行:将从文件读取到数据,直接通过response响应给客户端。

验证方式如下:

1. 启动服务器:打开命令行,进入js脚本所在的位置,执行:node e_ilinkit_1.js,如下所示:

2. 打开浏览器,输入:http://localhost:8000,显示如下:

当完成对客户端请求的响应之后,服务器端输出日志:文件读取完毕,如下所示:

改进1:

前面我们提到,读取文件时,使用的是用fs.createReadStream返回文件流,而给客户端响应数据的response对象,也像一个管道,

也像一个“流”,这么看,向客户端响应文件时,是不是将两个管道对接起来就OK了呢? NodeJS 还真有这样的机制。

下面我们来看一下改进之后的代码:

 var http = require( 'http' );
var fs = require('fs'); var file_path = "D:\\ilinkit_logo.png" ;
var file_stream; var server =http.createServer( function ( request ,response ){
file_stream = fs.createReadStream( file_path );
file_stream.pipe( response );
} );
server.listen( 8000 );
console.log( 'HTTP服务器启动中,端口:8000.....' );

重点看第9行:通过fs.createReadStream将文件数据流之后,直接调用pipe函数,file_stream.pipe( response ); 将文件中的数据响应给客户端。

相当于,你去中药房取药,之前的方式是:你到药房的窗口,把药方给里面的工作人员,工作人员依据药方的清单,到货架上一样一样的取药。全部取完之后,拿个袋子一装,然后跟你说:“都在这里了,您核对一下。”

改进之后呢?整个过程变得自动化,不需要工作人员一样一样的取药。你到窗口在按键上输入你的药单编号,然后里面的这个自动化程序如何做呢?用一个“管道”将一个“拣药”的窗口和你取药的窗口,用一个管子(pipe)一连接,自动化程序就不管这件事情了。“拣药程序”按药单拣了药之后,直接通过之前建立的“管道”将药送到你的面前。是不是大大简化了整个过程?

当然,这里举这个改进例子仅仅为了让大伙感受一下NodeJS处理‘流数据’的精巧之处,回到我们的iLinkIT的场景,我们后面会采用其他的方式。

改进2

回到开头小明的例子,张大爷走过来逗小明说:“我不要巧克力,我想要一个果冻。”小明到屋里找了一下,发现没有果冻,小明该怎么办?

同样,异常的处理也是NodeJS的重要特性,前文我们讲过,NodeJS是单进程、单线程的,所以,对于异常的处理需要十分谨慎。读取文件的时候,也有可能出现异常,比如:被读取的文件不存在。

现在,我们就增加异常处理机制,改进后的代码如下:

 var http = require( 'http' );
var fs = require('fs'); var file_path = "D:\\ilinkit_logo.png" ;
var file_stream ; var server =http.createServer( function ( request ,response ){
fs.stat( file_path , function ( err , stat ){
if (err) {
if ('ENOENT' == err.code) {
console.log( 'File does not exist...' );
response.end( 'File does not exist...' );
} else {
console.log( 'Read file exception...' );
response.end( 'Read file exception...' );
}
} else {
file_stream = fs.createReadStream( file_path );
file_stream.on( 'data' , function( chunk ){
response.write( chunk );
} );
file_stream.on( 'end' , function( ){
response.end( "" );
console.log( "文件读取完毕" );
} );
file_stream.on('error', function(err){
response.end( "文件读取失败!" );
});
}//end else,读取文件没有发生错误
});
} );
server.listen( 8000 );
console.log( 'HTTP服务器启动中,端口:8000.....' );

我们重点分析改进的部分:

第8行代码,通过fs.stat可以读取指定文件相关的信息,如果发生异常,则调用异常处理程序,第9行开始的代码;如果没有异常,则读取文件,用文件的内容响应客户端,从第17行开始。从这里可以看出NodeJS中异常处理的一个特点:通常会传入一个包含error对象的回调函数(这里声明为err),异常发生时,通过error对象可以获得异常相关的信息。

第10行到第13行,如果错误的类型是文件不存在,则告知客户端,文件不存在,并在服务端输出日志。

第13行到第16行,如果是其他的异常,则输出另外的提示内容。

第17行到第29行,代码逻辑,和前面的一样,就不再赘述。

验证方式:

1. 启动服务器:打开命令行,进入js脚本所在的位置,执行:node e_ilinkit_3.js

2. 打开浏览器,输入:http://localhost:8000,显示如下:

3. 现在,我们暂时将文件D:\ilinkit_logo.png删除,或者重命名。

打开浏览器,输入:http://localhost:8000,显示如下:

客户端得到的消息是:File does not exist....

【要点回顾】

今天的解说就到这里,我们一起来回顾一下要点:

1. 用fs模块来实现文件的读取。

2. 展示了fs的pipe机制。

3. 结合fs.stat展示了NodeJS异常处理的基本特征。

正如本系列文章所说,这一系列文章的目的是通过一个具体业务场景文件共享传送(iLinkIT),来描述NodeJS的特征,目的是学习。所以,采用一步一步、循序渐进地方式,以方便读者的理解,所以,整个系列文章也有如下特点:

1. 很多知识点没有深入展开讲

比如:我们讲了文件如何读取,但是没有讲文件如何写入。因为我们以一个具体的场景为主线,iLinkIT这个场景不涉及的,用不到的,可能就不会去展开讲。这一系列文章的定位是入门,展现NodeJS的精彩特性。如果想更深入地理解技术细节,在真正的项目中,建议读者参阅官方的社区网站,或更权威的技术指导书。

2. 过程中的思考不一定全面

我们在每一篇文章中,就聚焦几个点,某些地方可能就会简化处理。比如:这篇文章我们讲了如何读取文件,但是,为了简化框架,我们把要读取的文件路径固定写成D:\ilinkit_logo.png,其实,NodeJS也是支持命令传入参数的,但是,如果一下子就和盘托出,面面俱到,就不利于读者理解。

当然啦,正如开篇所述,大家如果有什么好的建议,非常欢迎留言交流,不胜感激^_^~~

-----------------------爱莲(iLinkIT)系列文章------------------------------------------

缘起爱莲:我要的,现在就要!

爱莲(iLinkIT)的架构与原理

遇见NodeJS:JavaScript的贵人

NodeJS服务器:一行代码 = 一个的HTTP服务器

NodeJS文件读取:感恩常在--抓把糖果,愉悦客人

NodeJS缓存机制:畅销货,就多囤一点呗

NodeJS安全设计:好吃的草莓味糖果,只给好朋友小红

NodeJS服务器退出:完成任务,优雅退出

NodeJS文件读取:感恩常在--抓把糖果,愉悦客人的更多相关文章

  1. nodejs 文件读取一行

    作者QQ:1095737364    QQ群:123300273     欢迎加入!   废话没有,直接上代码: app.get('/company', function (req, res, nex ...

  2. 1-2 nodejs小节 文件读取

    1.表达式 在命令行输入  node回车后,可以在后边输入相应的表达式,进行运算操作   2.阻塞文件读取 var data=fs.readFileSync('input.txt', 'utf-8') ...

  3. 用nodejs实现读取文件操作

    //如果不是全局就得引入fs成员 const fs = require("fs"); //fs 核心模块中提供了一个 fs.readFile方法,来读取指定目录下的文件 //fs. ...

  4. H5学习系列之文件读取API--本文转自http://blog.csdn.net/jackfrued/article/details/8967667

    HTML5定义了FileReader作为文件API的重要成员用于读取文件,根据W3C的定义,FileReader接口提供了读取文件的方法和包含读取结果的事件模型. FileReader的使用方式非常简 ...

  5. Linux学习笔记之文件读取过程

    0x00 概述 对于Linux系统来说,一切的数据都起源于磁盘中存储的文件.Linux文件系统的结构及其在磁盘中是如何存储的?操作系统是怎样找到这些文件进行读取的?这一章主要围绕这几个问题进行介绍(以 ...

  6. nodejs 文件操作

    前言: nodejs 自带的文件操作的模块  fs 就是对文件的增删查改: 就像我们用的服务器,我们没有办法在运行的文件上进行一直的修改,因为他不向浏览器,刷新后我们的文件会自己修改: 如果想要更改我 ...

  7. xctf-i-got-id-200(perl网页文件+ARGV上传造成任意文件读取)

    打开url发现有三个链接,点进去都是.pl文件,且只有files可以上传文件. .pl文件都是用perl编写的网页文件 这里上传了又将文件的内容全部打印出来,那么猜想后台应该用了param()函数. ...

  8. Mysql溯源-任意文件读取👻

    Mysql溯源-任意文件读取 前言 读了<MySQL蜜罐获取攻击者微信ID>的文章,文中说明了通过mysql蜜罐读取攻击者微信ID的过程,抱着学习的态度尝试了一下 原理 mysql中有一个 ...

  9. java中的文件读取和文件写出:如何从一个文件中获取内容以及如何向一个文件中写入内容

    import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.Fi ...

随机推荐

  1. C# is与as

    1.使用场景: 强制类型转换,有可能会导致异常.is与as就是为了解决这一问题,is与as永远不会抛出异常. 2.is判断一个对象是否兼容于指定的类型,考虑里氏代换.Dog是Animal,而Anima ...

  2. Codeforces Gym 100571A A. Cursed Query 离线

    A. Cursed QueryTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100571/problem ...

  3. Base64 图片转换工具

    以前在写asp的后台的时候,有一个上传功能是必须的,那时候进行的图片预览(未上传前)其实就是获取本地的图片路径来显示图片,但是随着HTML5的出现,可以把图片通过编码来实现预览. 在雅虎的36条速度优 ...

  4. nginx配置图片服务器

    这几天研究了一下nginx配置图片服务器的相关内容,个人的一些收获与大家分享一下: Nginx是目前非常流行的web服务器,它起源于俄罗斯.它具有处理速度快,并发量大,占用资源极低等优点,尤其对于静态 ...

  5. js获取网络图片的宽和高

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. iOS开发——UI篇OC篇&TextField作为搜索框的使用

    TextField作为搜索框的使用 在iOS开发中我们经常会使用到搜索框,但是有的时候系统自带的搜索框不足以满足我吗想要的功能,这个时候我们就可以使用自定义的搜索框实现想要的功能. 今天就简单的介绍一 ...

  7. Seconds_Behind_Master

    http://blog.chinaunix.net/uid-28212952-id-3494560.html 今天同事遇到一个故障,xtrabackup备份中flush tables with rea ...

  8. Spark之路 --- Windows Scala 开发环境安装配置

    JDK安装 JDK安装包下载 到Oracle官网下载JDK. 传送门 下载之前要记得勾选上同意协议然后选择相应的版本(Windows/Linux, 32/64) JDK安装及验证 按提示完成安装,安装 ...

  9. #pragma_pack(n)_与___attribute(aligned(n))

    #pragma pack(n) 与 __attribute(aligned(n))   在C语言中,结构是一种复合数据类型,其构成元素既可以是基本数据类型(如int.long.float等)的变量,也 ...

  10. Apache服务器中配置虚拟机的方法

    新浪微博虚拟机开发配置步骤及介绍.1.由于后面虚拟机中需要用到Rewrite所以先编辑Apache的conf目录下的httpd.conf文件.(可根据实际需要操作)添加mod_rewrite.so模块 ...