`
天梯梦
  • 浏览: 13732948 次
  • 性别: Icon_minigender_2
  • 来自: 洛杉矶
社区版块
存档分类
最新评论

Node.js: fs.readFile/writeFile 和 fs.createReadStream/writeStream 区别

 
阅读更多

1. 先说说各自的用法:

How do I read files in node.js?

fs = require('fs');
fs.readFile(file, [encoding], [callback]);

// file = (string) filepath of the file to read

 

encoding is an optional parameter that specifies the type of encoding to read the file. Possible encodings are 'ascii', 'utf8', and 'base64'. If no encoding is provided, the default is utf8.

 

callback is a function to call when the file has been read and the contents are ready - it is passed two arguments, error and data. If there is no error, error will be null and data will contain the file contents; otherwise err contains the error message.

So if we wanted to read /etc/hosts and print it to stdout (just like UNIX cat):

fs = require('fs')
fs.readFile('/etc/hosts', 'utf8', function (err,data) {
  if (err) {
    return console.log(err);
  }
  console.log(data);
});

 

The contents of /etc/hosts should now be visible to you, provided you have permission to read the file in the first place.

 

Let's now take a look at an example of what happens when you try to read an invalid file - the easiest example is one that doesn't exist.

fs = require('fs');
fs.readFile('/doesnt/exist', 'utf8', function (err,data) {
  if (err) {
    return console.log(err);
  }
  console.log(data);
});

 

This is the output:

{ stack: [Getter/Setter],
  arguments: undefined,
  type: undefined,
  message: 'ENOENT, No such file or directory \'/doesnt/exist\'',
  errno: 2,
  code: 'ENOENT',
  path: '/doesnt/exist' }

 

How to use fs.createReadStream?

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

http.createServer(function(req, res) {
  // The filename is simple the local directory and tacks on the requested url
  var filename = __dirname+req.url;

  // This line opens the file as a readable stream
  var readStream = fs.createReadStream(filename);

  // This will wait until we know the readable stream is actually valid before piping
  readStream.on('open', function () {
    // This just pipes the read stream to the response object (which goes to the client)
    readStream.pipe(res);
  });

  // This catches any errors that happen while creating the readable stream (usually invalid names)
  readStream.on('error', function(err) {
    res.end(err);
  });
}).listen(8080);

 

2. 区别:

createReadStream是给你一个ReadableStream,你可以听它的'data',一点一点儿处理文件,用过的部分会被GC(垃圾回收),所以占内存少。 readFile是把整个文件全部读到内存里。

nodejs的fs模块并没有提供一个copy的方法,但我们可以很容易的实现一个,比如:

var source = fs.readFileSync('/path/to/source', {encoding: 'utf8'});
fs.writeFileSync('/path/to/dest', source);

 

这种方式是把文件内容全部读入内存,然后再写入文件,对于小型的文本文件,这没有多大问题,比如grunt-file-copy就是这样实现的。但是对于体积较大的二进制文件,比如音频、视频文件,动辄几个GB大小,如果使用这种方法,很容易使内存“爆仓”。理想的方法应该是读一部分,写一部分,不管文件有多大,只要时间允许,总会处理完成,这里就需要用到流的概念

Stream在nodejs中是EventEmitter的实现,并且有多种实现形式,例如:

  • http responses request
  • fs read write streams
  • zlib streams
  • tcp sockets
  • child process stdout and stderr

上面的文件复制可以简单实现一下:

var fs = require('fs');
var readStream = fs.createReadStream('/path/to/source');
var writeStream = fs.createWriteStream('/path/to/dest');

readStream.on('data', function(chunk) { // 当有数据流出时,写入数据
    writeStream.write(chunk);
});

readStream.on('end', function() { // 当没有数据时,关闭数据流
    writeStream.end();
});

 

上面的写法有一些问题,如果写入的速度跟不上读取的速度,有可能导致数据丢失。正常的情况应该是,写完一段,再读取下一段,如果没有写完的话,就让读取流先暂停,等写完再继续,于是代码可以修改为:

var fs = require('fs');
var readStream = fs.createReadStream('/path/to/source');
var writeStream = fs.createWriteStream('/path/to/dest');

readStream.on('data', function(chunk) { // 当有数据流出时,写入数据
    if (writeStream.write(chunk) === false) { // 如果没有写完,暂停读取流
        readStream.pause();
    }
});

writeStream.on('drain', function() { // 写完后,继续读取
    readStream.resume();
});

readStream.on('end', function() { // 当没有数据时,关闭数据流
    writeStream.end();
});

 

或者使用更直接的pipe

// pipe自动调用了data,end等事件
fs.createReadStream('/path/to/source').pipe(fs.createWriteStream('/path/to/dest'));

 

下面是一个更加完整的复制文件的过程

var fs = require('fs'),
    path = require('path'),
    out = process.stdout;

var filePath = '/Users/chen/Movies/Game.of.Thrones.S04E07.1080p.HDTV.x264-BATV.mkv';

var readStream = fs.createReadStream(filePath);
var writeStream = fs.createWriteStream('file.mkv');

var stat = fs.statSync(filePath);

var totalSize = stat.size;
var passedLength = 0;
var lastSize = 0;
var startTime = Date.now();

readStream.on('data', function(chunk) {

    passedLength += chunk.length;

    if (writeStream.write(chunk) === false) {
        readStream.pause();
    }
});

readStream.on('end', function() {
    writeStream.end();
});

writeStream.on('drain', function() {
    readStream.resume();
});

setTimeout(function show() {
    var percent = Math.ceil((passedLength / totalSize) * 100);
    var size = Math.ceil(passedLength / 1000000);
    var diff = size - lastSize;
    lastSize = size;
    out.clearLine();
    out.cursorTo(0);
    out.write('已完成' + size + 'MB, ' + percent + '%, 速度:' + diff * 2 + 'MB/s');
    if (passedLength < totalSize) {
        setTimeout(show, 500);
    } else {
        var endTime = Date.now();
        console.log();
        console.log('共用时:' + (endTime - startTime) / 1000 + '秒。');
    }
}, 500);

 

可以把上面的代码保存为copy.js试验一下

我们添加了一个递归的setTimeout(或者直接使用setInterval)来做一个旁观者,每500ms观察一次完成进度,并把已完成的大小、百分比和复制速度一并写到控制台上,当复制完成时,计算总的耗费时间。

结合nodejs的readlineprocess.argv等模块,我们可以添加覆盖提示、强制覆盖、动态指定文件路径等完整的复制方法,有兴趣的可以实现一下,实现完成,可以

ln -s /path/to/copy.js /usr/local/bin/mycopy

 

这样就可以使用自己写的mycopy命令替代系统的cp命令。

更多fs说明,可以查看API: http://nodeapi.ucdok.com/#/api/fs.html

 

原文转自:Node.js: fs.readFile/writeFile 和 fs.createReadStream/writeStream 区别

 

 

 

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    Node.js教程/中文文档/开发指南pdf

    5. **文件系统操作**:Node.js的FS模块提供了丰富的API用于读写文件、目录操作等,如`fs.readFile()`、`fs.writeFile()`、`fs.readdir()`等,这些操作都是异步的,确保不会阻塞程序执行。 6. **网络编程**:Node.js...

    nodejs异步IO的实现 转:http://cnodejs.org/topic/4f16442ccae1f4aa2700113b

    以文件读写为例,我们可以使用`fs`模块中的异步方法,如`fs.readFile()`和`fs.writeFile()`。这些方法接受一个回调函数作为参数,当文件读取或写入完成后,回调函数会被调用。例如: ```javascript const fs = ...

    《Node入门一本全面地Node.js教程》PDF

    - **读写文件**:`fs`模块提供了读取和写入文件的功能,包括同步和异步方法,如`fs.readFile()`和`fs.writeFile()`。 - **流操作**:Node.js中的流可以有效地处理大量数据,如读取大文件或网络传输。 4. **网络...

    Node.js-StuQ分享专题《深入浅出jsNode.js异步流程控制》完整版

    在IT行业中,Node.js是一个基于Chrome V8引擎的JavaScript运行环境,它以其高效、轻量级和非阻塞I/O模型而备受推崇,尤其适用于构建网络应用和服务。本专题《深入浅出js(Node.js)异步流程控制》将探讨Node.js中的...

    浅谈Node.js:fs文件系统模块

    Node.js中的fs(文件系统)模块是一个用于与文件系统进行交互的核心模块,它为应用程序提供了直接读取、写入和修改文件的功能。fs模块允许开发者执行多种文件操作,包括但不限于创建、读取、写入、追加内容以及检测...

    gistfs.js:用于 writeFile 和 readFile 的 Github gist API 包装器

    它提供了一个类似于 node.js fs.readFile和fs.writeFile的接口。 限制 目前只会读取小于 1Mb 的文件 参数 范围 类型 描述 repo 八爪鱼 从 Octokat 返回的无效回购调用octo.gists('gist_id') 。 有关示例,请参见...

    Node.js初级+进阶

    `fs`模块提供了文件系统的异步操作API,如`fs.readFile()`和`fs.writeFile()`等,用于读写文件,这些方法都接受一个回调函数作为参数。 ### 6. Buffer对象 Buffer是Node.js中的核心类,用于处理二进制数据。在处理...

    hubfs.js:用于 writeFile 和 readFile 的 Github API 包装器

    它复制了 node.js fs.readFile和fs.writeFile 。 它有几个特别之处: 最小化请求 默认情况下,它尝试使用 Github读取、写入单个请求并使用 3 个请求更新文件:(a) 尝试写入; (b) 获取现有文件的 sha; (c) 写入...

    超全面Node.js面试真题-71页.pdf

    Node.js 是一种基于 Chrome V8 引擎的服务器端 JavaScript 运行环境,它使得开发者能够在服务器端使用 JavaScript 语言,极大地拓宽了 JavaScript 的应用范围。Node.js 的核心特性包括事件驱动、非阻塞I/O模型,这...

    Node.js 中文手册

    例如,`fs.readFile`用于异步读取文件,`fs.writeFile`用于异步写入文件,这些API都遵循Node.js的非阻塞I/O原则。 **5. 网络编程** Node.js 内置了HTTP服务器模块,可以方便地创建高性能的Web服务器。通过`...

    Notes_Node.js:Node.js 中的简单本地笔记应用

    3. **文件系统**: Node.js内置了对文件系统的操作API,如`fs.readFile`和`fs.writeFile`,可以在应用中轻松地进行文件读写操作,这对于本地笔记应用至关重要。 4. **Express框架**: 在Node.js中,常用Express作为...

    Node.js-FirefoxSend文件共享实验允许您将加密文件发送给其他用户

    - `fs.readFile()` 和 `fs.writeFile()`:分别用于读取和写入文件。这两个异步方法在处理大文件时特别有用,因为它们不会阻塞程序执行。 - `fs.appendFile()`:用于向文件追加数据,而不会覆盖原有内容。 - `fs....

    node.js教程文档

    《Node.js教程文档》是针对JavaScript后端开发框架Node.js的一份详尽学习资料,它包含API文档和实例,以英文形式呈现,旨在帮助开发者深入理解和应用Node.js。本教程覆盖了从基础到进阶的各种知识点,对于想要踏入...

    node.js 追加写入 文件删除 打开与关闭 创建 读取 删除 修改.zip

    使用`fs.readFile()`或`fs.createReadStream()`读取文件内容。例如: ```javascript const fs = require('fs'); fs.readFile('example.txt', 'utf8', (err, data) =&gt; { if (err) throw err; console.log('文件...

    node.js 传智播客 第1天第2部分共2部分 共8天

    通过`fs.readFile()`和`fs.writeFile()`等方法,我们可以实现对文件内容的读写操作。而`fs.readdir()`则用于获取目录中的文件列表,这对于构建文件管理系统至关重要。 其次,课程会深入讲解Node.js的事件循环机制。...

    Node.js 核心编程

    6. **文件系统操作**:Node.js提供了丰富的文件系统API,如`fs.readFile`、`fs.writeFile`、`fs.readdir`等,用于读写文件和目录操作,这对于实现音乐播放器的功能至关重要。 7. **流处理**:Node.js中的流是处理...

    Node.js核心库

    - 示例:`fs.readFile()`、`fs.writeFile()`、`fs.readdir()`等。 4. **网络编程** - `http`模块:用于创建HTTP服务器和客户端,实现Web服务。 - `net`模块:底层网络通信,可用于创建TCP或UDP服务器和客户端。 ...

    Node.js-node.js模拟实现一个简单的文件系统

    1. `fs.readFile()` 和 `fs.writeFile()`:分别用于异步读取和写入文件内容。 2. `fs.appendFile()`:追加内容到文件末尾。 3. `fs.unlink()`:删除文件。 4. `fs.mkdir()` 和 `fs.rmdir()`:创建和删除目录。 5. `...

    node.js:节点代码与笔记

    Node.js是一种基于Chrome V8引擎的JavaScript运行环境,它允许开发者在服务器端使用JavaScript进行编程。这个"node.js:节点代码与笔记"很可能是包含了关于Node.js的学习资料、示例代码以及作者的个人笔记,旨在帮助...

Global site tag (gtag.js) - Google Analytics