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

栏目: Node.js · 发布时间: 6年前

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

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

需求

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

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


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

云攻略

云攻略

马克·贝尼奥夫、卡莱尔·阿德勒 / 徐杰 / 海天出版社 / 2010年8月 / 36.00元

Apple、Google、甲骨文、腾讯 都已投入了云的怀抱, 你还在等什么? 快来加入我们! 最初,Salesforce.com 只是一间小小的租赁公寓 在短短10年内 它已成长为 世界上发展最快、最具创新力的 产业变革领导者 曾经,这是个软件为王的时代。 现在,这是个云计算的新时代。 NO SOFTWARE 抛弃软件的......一起来看看 《云攻略》 这本书的介绍吧!

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具