首 页最新软件下载排行文章资讯投稿发布下载专题
维维下载站
您的位置:首页编程开发网页制作Javascript → Node.js本地文件操作实例:文件拷贝与目录遍历

Node.js本地文件操作实例:文件拷贝与目录遍历

来源:本站整理 发布时间:2016-2-16 17:09:57 人气:

本文主要为大家详细介绍了Node.js本地文件操作之文件拷贝与目录遍历的例子方法,拷贝用到了Node的文件API,遍历则举了一个异步API实现的形式(Node的一大特点),有兴趣的快点来看一看吧。
 

文件拷贝
NodeJS 提供了基本的文件操作 API,不过像文件拷贝这种高级功能就没有提供,因此我们先拿文件拷贝程序练手。与 copy 命令类似,我们的程序需要可以接受源文件路径与目标文件路径两个参数。

小文件拷贝
我们使用 NodeJS 内置的 fs 模块简单实现这一程序如下。

var fs = require('fs');

function copy(src, dst) {
  fs.writeFileSync(dst, fs.readFileSync(src));
}

function main(argv) {
  copy(argv[0], argv[1]);
}

main(process.argv.slice(2));

以上程序使用 fs.readFileSync 从源路径读取文件内容,并且使用 fs.writeFileSync 将文件内容写入目标路径。

豆知识: process 是一个全局变量,可通过 process.argv 获得命令行参数。由于 argv[0] 固定等于 NodeJS 执行程序的绝对路径,argv[1] 固定等于主模块的绝对路径,所以第一个命令行参数从 argv[2] 这个位置开始。

大文件拷贝
上边的程序拷贝一些小文件没什么问题,不过这种一次性将所有文件内容都读取到内存中后再一次性写入磁盘的方式并不适合拷贝大文件,内存会爆仓的。对于大文件,我们只能读一点写一点,直到完成拷贝。所以上边的程序需要改造如下。

var fs = require('fs');

function copy(src, dst) {
  fs.createReadStream(src).pipe(fs.createWriteStream(dst));
}

function main(argv) {
  copy(argv[0], argv[1]);
}

main(process.argv.slice(2));

以上程序使用 fs.createReadStream 创建了一个源文件的只读数据流,并且使用 fs.createWriteStream 创建了一个目标文件的只写数据流,而且用 pipe 方法将两个数据流连接起来了。连接起来以后发生的事情,说得抽象一点的话,水顺着水管从一个桶流到了另一个桶里了。

遍历目录

遍历目录是操作文件时的一个常见需求。例如写一个程序,需要找到并且处理指定目录下的所有JS文件时,就需要遍历整个目录。

递归算法
遍历目录时一般使用递归算法,否则就难以编写出简洁的代码。递归算法与数学归纳法类似,通过不断缩小问题的规模来解决问题。以下示例说明了这一方法。

function factorial(n) {
  if (n === 1) {
    return 1;
  } else {
    return n * factorial(n - 1);
  }
}

上边的函数用于计算 N 的阶乘(N!)。可以看到,当 N 大于 1 时,问题简化为计算 N 乘以 N-1 的阶乘。当 N 等于 1 时,问题达到最小规模,不需要再简化,因此直接返回 1。

陷阱: 使用递归算法编写的代码虽然简洁,不过因为每递归一次就产生一次函数调用,在需要优先考虑性能时,需要将递归算法转换为循环算法,以减少函数调用次数。

遍历算法
目录是一个树状结构,在遍历时通常使用深度优先+先序遍历算法。深度优先,意味着到达一个节点以后,首先接着遍历子节点而不是邻居节点。先序遍历,意味着第一次到达了某节点就算遍历完成,而并非是最后一次返回某节点才算数。所以使用这种遍历方式的时候,下边这棵树的遍历顺序是 A > B > D > E > C > F。

A
     / \
    B  C
    / \  \
   D  E  F

同步遍历
了解了必要的算法以后,下面可以简单地实现以下目录遍历函数。

function travel(dir, callback) {
  fs.readdirSync(dir).forEach(function (file) {
    var pathname = path.join(dir, file);

    if (fs.statSync(pathname).isDirectory()) {
      travel(pathname, callback);
    } else {
      callback(pathname);
    }
  });
}

可以看到,该函数以某一个目录作为遍历的起点。遇到一个子目录时,就先接着遍历子目录。遇到一个文件时,就将文件的绝对路径传给回调函数。回调函数拿到文件路径以后,就可以做各种判断和处理。因此假如有以下目录:

- /home/user/
  - foo/
    x.js
  - bar/
    y.js
  z.css

使用以下代码遍历该目录时,得到的输入如下。

travel('/home/user', function (pathname) {
  console.log(pathname);
});
/home/user/foo/x.js
/home/user/bar/y.js
/home/user/z.css

异步遍历
要是读取目录或读取文件状态的时候使用的是异步API,目录遍历函数实现起来会有些复杂,不过原理完全一样。travel函数的异步版本如下。

function travel(dir, callback, finish) {
  fs.readdir(dir, function (err, files) {
    (function next(i) {
      if (i < files.length) {
        var pathname = path.join(dir, files[i]);

        fs.stat(pathname, function (err, stats) {
          if (stats.isDirectory()) {
            travel(pathname, callback, function () {
              next(i + 1);
            });
          } else {
            callback(pathname, function () {
              next(i + 1);
            });
          }
        });
      } else {
        finish && finish();
      }
    }(0));
  });
}
相关下载
栏目导航
本类热门阅览