NodeJS 将文件夹按照存放路径变成一个对应的JSON的方法


Posted in NodeJs onOctober 17, 2018

在编程之前,一定要有一个信条:代码是为了减少工作量而生的,重复枯燥的工作是不能容忍的。

需求

这是由上篇文章衍生出的需求,我已经将一个文件夹内所有的文件名转译为英文,但我在页面上还需要将这些图片引入加载。如果一个一个手写到程序里,未免有点劳心劳神。那么何不将这个文件夹按照存放路径变成一个相应的JSON在前端请求并渲染呢?

说干就干。

文件夹的路径如下所示:

一级路径:test
二级路径:A,B,C...共十三个文件夹
三级路径:每个二级路径下有3-8个文件夹不等
四级路径:a.jpg,b.jpg,c.jpg等数量不等的图片文件

思路

1.一个全局变量:数组类型obj。

2.递归遍历目录,是文件夹的取出名字,建立一个对象,放入文件夹名name和一个空数组list,如

{
  name:'fileName',
  list:[]//用来存放下属路径
}

3.依次重复步骤2,直至寻找到路径下的文件,将文件名name和拼合好的路径src放入归属的list中,如下:

list:[
  {
    name:'fileName',
    src:'filePath'
  }
]

实践

语言

NodeJS

需求模块
fs/async。

代码 先上代码,逻辑解析在提示补上。

(function() {
 Array.prototype.distinct = function() {
 var arr = this,
  result = [],
  i,
  j,
  len = arr.length;
 for (i = 0; i < len; i++) {
  for (j = i + 1; j < len; j++) {
  if (arr[i].name === arr[j].name) {
   j = ++i;
  }
  }
  result.push(arr[i]);
 }
 return result;
 }
 // 主业务代码
 var fs = require("fs");
 var async = require('async');
 var obj = [];
 var search = function(src) {
 // 读取目录中的所有文件/目录
 fs.readdir(src, function(err, paths) {
  if (err) {
  throw err;
  }
  paths.forEach(function(path) {
  var _src = src + '/' + path;
  fs.stat(_src, function(err, st) {
   if (err) {
   throw err;
   }
   // 判断是否为文件
   if (st.isFile()) {
   async.forEachLimit(obj, 1000, function(item, callback) {
    if (src.match(new RegExp(item.name))) {

    item.list.forEach(function(iv) {
     if (src.match(new RegExp(iv.name))) {
     iv.list.push({
      name: path.split('.')[0],
      src: _src
     })

     }

    })
    }
    callback(null, item)
   })
   obj = obj.distinct();
   fs.writeFile("main.json", JSON.stringify(obj), "utf-8", (error) => {
    //监听错误,如正常输出,则打印null
    if (error == null) {
    obj = null;

    }

   });
   }
   // 如果是目录则递归调用自身
   else if (st.isDirectory()) {
   if (obj.length <= 0) {
    obj.push({
    name: path,
    list: []
    })
   } else {
    var value = paths;
    async.forEachLimit(obj, 1000, function(item, callback) {
    //如果数组里已有
    if (src.match(new RegExp(item.name))) {
     item.list.push({
     name: path,
     list: []
     })
    } else {
     value.forEach(function(vv) {
     if (vv == item.name) {
      obj.push({
      name: path,
      list: []
      })
     } else {}
     })
    }
    callback(null, item)
    }, function(err) {
    if (err) throw err;
    })
   }
   exists(_src, search);

   }
  });
  });
 });
 };
 var exists = function(src, callback) {
 callback(src);
 };
 exists('./test2', search);
})();

提示

首先,要有心理准备,这个轮子里使用了递归+很多遍历,这对于内存占用是很严重的,尤其是我们还有一个 全局变量OBJ ,如果逻辑处理不好很容易会出现错误内存溢出。这也是为什么我引入了async模块的理由。

在引入模块之后,第一步要着眼于判断为文件夹后的函数:

//如果obj为空,说明我们是第一次进入函数,那么插入一个新的元素
if (obj.length <= 0) {
 obj.push({
 name: path,
 list: []
 })
}

async.forEachLimit是异步串行函数,可以同批次运行指定数量的代码,可以避免一次遍历太多,里面的参数依次为(数组,指定的数量,执行函数,错误回调)。

下面代码中的参数很多,如paths,path,src,_src等,打代码的时候经常会让我头脑不清晰,这也侧面告诫了我一个问题,同一作用域内不宜有太多处理函数。

//如果路径参数src里匹配到了obj中元素的name,说明数组里已经有了上级文件夹,则向此上级文件夹内插入此时的文件夹名path
if (src.match(new RegExp(item.name))) {
 item.list.push({
 name: path,
 list: []
 })
} 

/*如果没有上级文件夹,那往尾部插入新的元素
 *进行一次遍历排查,去除掉二级路径向尾部插入的举动*/

value.forEach(function(vv) {
 if (vv == item.name) {
 obj.push({
  name: path,
  list: []
 })
 } else {}
})

对我来说,这段代码是一段丑陋的函数,处理方法过于粗糙,并且占用了不必要的内存空间,更严重的是,拖累了整体文件的运行速度,但时间仓促,加之能力菜的真实,暂时还尚未想出解决方案。

还要备注的是,这里本来想达到的去重判断因为上级方法套用的遍历次序不同,造成我只完成了初级的防止push重复,却又有了递归式的重复。有兴趣的朋友在使用这个demo时可以将首行的去重方法删除,看看效果。

处理好了文件夹状态下的方法,来看看已经到了四级路径的处理

//src是此时运行的search方法内的文件路径参数,对item.name也就是二级路径的文件名进行匹配,如果正确,则对三级路径下的文件名进行匹配(本来我想在这里写递归或者回调的,太懒取消原计划)。全部都匹配正确,则往内插入文件名和文件路径
async.forEachLimit(obj, 1000, function(item, callback) {
 if (src.match(new RegExp(item.name))) {
 item.list.forEach(function(iv) {
  if (src.match(new RegExp(iv.name))) {
  iv.list.push({
   name: path.split('.')[0],
   src: _src
  })
  }
 })
 }
 callback(null, item)
})

函数到这里时,就是最后一步,写入json文件了,不能忘记的是,这里需要进行一次去重,原因在上文提到了,方法在函数行首。

PS:在运行结束之后,一定要将全局变量清空,虽然我暂时尚未遇到因此理由内存的崩溃,但可以预见到的是,在用于庞大文件夹时,势必会对内存有很大的伤害。

obj = obj.distinct();
fs.writeFile("main.json", JSON.stringify(obj), "utf-8", (error) => {
 //监听错误,如正常输出,则打印null
 if (error == null) {
 obj = null;
 }
});

END

这篇小笔记就结束了,这个轮子遇到的问题很浅显,但值得重视。对我将来写大型单页应用或是系统型网站非常有借鉴意义,所以此篇文章的漏洞和错误,我会再次进行排查,以达到最优的解决方法。我在这里抛砖引玉,诚恳希望各位同仁前辈能不吝赐教!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

NodeJs 相关文章推荐
nodejs中简单实现Javascript Promise机制的实例
Dec 06 NodeJs
NodeJS与HTML5相结合实现拖拽多个文件上传到服务器的实现方法
Jul 26 NodeJs
Nodejs 搭建简单的Web服务器详解及实例
Nov 30 NodeJs
nodejs进阶(6)—连接MySQL数据库示例
Jan 07 NodeJs
nodejs个人博客开发第四步 数据模型
Apr 12 NodeJs
详解nodejs微信公众号开发——6.自定义菜单
Apr 13 NodeJs
nodejs入门教程三:调用内部和外部方法示例
Apr 24 NodeJs
Nodejs回调加超时限制两种实现方法
Jun 09 NodeJs
nodejs前端自动化构建环境的搭建
Jul 26 NodeJs
nodejs超出最大的调用栈错误问题
Dec 27 NodeJs
NodeJS 实现多语言的示例代码
Sep 11 NodeJs
nodejs异步编程基础之回调函数用法分析
Dec 26 NodeJs
Nodejs实现多文件夹文件同步
Oct 17 #NodeJs
深入理解NodeJS 多进程和集群
Oct 17 #NodeJs
CentOS7中源码编译安装NodeJS的完整步骤
Oct 13 #NodeJs
NodeJS加密解密及node-rsa加密解密用法详解
Oct 12 #NodeJs
NodeJS使用Range请求实现下载功能的方法示例
Oct 12 #NodeJs
nodejs实现范围请求的实现代码
Oct 12 #NodeJs
NodeJS搭建HTTP服务器的实现步骤
Oct 12 #NodeJs
You might like
PHP中simplexml_load_string函数使用说明
2011/01/01 PHP
php适配器模式介绍
2012/08/14 PHP
PHP使用Pthread实现的多线程操作实例
2015/11/14 PHP
PHP统计目录中文件以及目录中目录大小的方法
2016/01/09 PHP
微信公众平台开发-微信服务器IP接口实例(含源码)
2017/03/05 PHP
FF IE兼容性的修改小结
2009/09/02 Javascript
围观tangram js库
2010/12/28 Javascript
Javascript核心读书有感之语句
2015/02/11 Javascript
基于Vue实现拖拽效果
2018/04/27 Javascript
vue中的数据绑定原理的实现
2018/07/02 Javascript
解决vue2.0 element-ui中el-upload的before-upload方法返回false时submit()不生效问题
2018/08/24 Javascript
Vue实现简易翻页效果源码分享
2018/11/08 Javascript
原生js实现移动端Touch轮播图的方法步骤
2019/01/03 Javascript
Javascript实现鼠标移入方向感知
2020/06/24 Javascript
[01:55]2014DOTA2国际邀请赛 BBC正赛第一天总结
2014/07/10 DOTA
python+numpy+matplotalib实现梯度下降法
2018/08/31 Python
Python判断一个三位数是否为水仙花数的示例
2018/11/13 Python
详解python:time模块用法
2019/03/25 Python
pyqt5 实现工具栏文字图片同时显示
2019/06/13 Python
Python内存管理实例分析
2019/07/10 Python
pytorch多进程加速及代码优化方法
2019/08/19 Python
Python 时间戳之获取整点凌晨时间戳的操作方法
2020/01/28 Python
python安装dlib库报错问题及解决方法
2020/03/16 Python
python 双循环遍历list 变量判断代码
2020/05/04 Python
Python爬虫开发与项目实战
2020/12/16 Python
使用Filters滤镜弥补CSS3的跨浏览器问题以及兼容低版本IE
2013/01/23 HTML / CSS
使用html5+css3来实现slider切换效果告别javascript+css
2013/01/08 HTML / CSS
乌克兰第一的珠宝网上商店:Gold.ua
2019/11/29 全球购物
SOA的常见陷阱或者误解是什么
2014/10/05 面试题
俄语翻译实习生的自我评价分享
2013/11/06 职场文书
新学期开学标语
2014/06/30 职场文书
执法作风整顿剖析材料
2014/10/11 职场文书
2014矛盾纠纷排查调处工作总结
2014/12/09 职场文书
创业计划书之o2o水果店
2019/08/30 职场文书
python 实现图与图之间的间距调整subplots_adjust
2021/05/21 Python
教你怎么用python实现字符串转日期
2021/05/24 Python