使用Node.js的fs.readFile()实现读取文件功能

 

简介

在我们了解的所有编程语言中绝大多数最常见的功能操作之一就是打开并读取一个文件。对于一般的大部分后段编程语言而已,这是非常简单的。对于JavaScript来说有点点出入,众所周知,JavaScript只能在浏览器中使用,大部分前端开发人员可能只熟悉FileReader API或类似功能

其实Node.js与浏览器中的典型JavaScript有很大不同。它有自己的一套库,用于处理操作系统和文件系统任务,如打开和读取文件。本文中我们实现下Node.js(使用fs模块)来读取文件

使用fs模块打开和读取文件有两种方法:

  • 一次加载所有内容(缓冲)
  • 增量加载内容(流)

 

使用Node.js的fs.readFile()实现读取文件功能

用fs.readFile缓冲读取内容

这是使用Node.js读取文件的最常见方法,特别适合初学者,因为它简单方便。不过它不一定是最好的或最有效的

下面是一个使用fs.readFile的简单示例:

var fs = require('fs');

fs.readFile('test-file.txt', 'utf8', function(err, data) {  
    if (err) throw err;
    console.log(data);
});

回调的data参数包含以utf8格式的字符串表示的文件的完整内容。如果完全省略utf8参数,那么该方法将只返回缓冲区对象中的原始内容

删除上面代码中的utf8参数(假设test-file.txt包含字符串“hello world!”),我们将得到:

使用Node.js的fs.readFile()实现读取文件功能 - 豆豆网

你可能已经注意到fs.readFile返回回调中的内容,这意味着该方法是异步运行的。在可能的情况下,都应该使用它来避免阻塞主执行线程,但有时必须同步执行某些读取操作,在这种情况下,我们可以使用Node提供的 readFileSync 方法

此方法的工作方式与之前完全相同,只是文件内容直接从函数调用返回,并且在加载文件时阻塞执行线程。通常在程序的启动部分(比如加载配置文件时)或命令行应用程序(阻塞主线程并不是很大问题)中使用这种方法

下面是如何使用Node同步加载文件:

var fs = require('fs');

try {  
    var data = fs.readFileSync('test-file.txt', 'utf8');
    console.log(data);    
} catch(e) {
    console.log('Error:', e.stack);
}

注意,对于阻塞(同步)调用,我们必须使用try…catch处理任何错误,不像非阻塞(异步)版本,错误作为参数传递给我们

除了这些方法返回数据和处理错误的方式外,它们的实现方式基本相同

 

使用fs.createReadStream增量加载内容(流)

打开和读取文件的第二种方法是使用fs.createReadStream 方法将其作为流( Stream )打开。所有节点流都是 EventEmitter 对象的实例,允许你监听重要的事件

一个可读的流对象有很多用处,其中包括:

  • 更小的内存占用。由于目标文件的数据是以块的形式加载的,因此在缓冲区中存储数据所需的内存并不多
  • 更快的响应时间。对于时间敏感的应用程序,请求和响应之间的时间非常关键。流减少了响应时间(特别是对于大文件),因为它们不需要等待加载整个文件之后才返回数据
  • 管道数据。流抽象允许使用数据生产者和消费者之间的公共接口通过管道传递数据。这与 Unix pipe 的概念非常相似

虽然使用流并不是很难,但是它们可能有点麻烦,而且不如fs.readFile方法那么直观。以下是“hello world!”的文件流:

var fs = require('fs');

var data = '';

var readStream = fs.createReadStream('test-file.txt', 'utf8');

readStream.on('data', function(chunk) {  
    data += chunk;
}).on('end', function() {
    console.log(data);
});

这段代码的功能与第一部分中的代码完全相同,只是我们必须在将数据打印到控制台之前“收集”数据块。如果你的文件相当小,那么你可能只会接收单个块,但是对于较大的文件,如音频和视频,将不得不收集多个块。在这种情况下,你必须要注意流文件的实际体量了

注意,上面展示的示例其实违背了使用流的初衷,因为我们最终在缓冲区(变量)中收集数据,但至少它让你了解了它们是如何工作的。下面提供一个更好的例子来展示文件流的优势。一个处理文件请求的Express路由:

var fs = require('fs');  
var path = require('path');  
var http = require('http');

var staticBasePath = './static';

var staticServe = function(req, res) {  
    var fileLocal = path.resolve(staticBasePath);
    fileLocal = path.join(fileLocal, req.url);

        var stream = fs.createReadStream(fileLocal);

        stream.on('error', function(error) {
            res.writeHead(404, 'Not Found');
            res.end();
        });

        stream.pipe(res);
};

var httpServer = http.createServer(staticServe);  
httpServer.listen(8080);  

我们在这里所做的就是用fs.createReadStream打开文件,并创建管道传输到响应对象res。我们甚至可以监听错误事件,并进行有效的处理。这算一个更好的处理读取文件的方法了

 

结论

以上可以使你了解一些读取文件的基础知识,以及使用流对象的一些高级加载方法,并且知道什么时候使用。当然了,对于内存受限或时间受限的应用程序,你应该仔细考虑下~

 

转载请注明出处豆豆网

欢迎分享至:

版权声明:原创文章自由转载-非商用-非衍生-保持署名及文章出处(创意共享3.0许可证
转载说明:转载请注明出处豆豆网
部分文章选自网络(文首、末未标明豆豆网的均来自网络),我们对文中观点保持中立,本站涉及软件下载,仅供参考学习、交流之目的,涉及版权请告知删除,邮箱地址:豆豆网博客


发表评论

电子邮件地址不会被公开。 必填项已用*标注