PHP开源Hub
致力于开发者的提升

NodeJS:将文件夹按照存放路径变成一个对应的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

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

作者:维伦
来源:掘金

赞(2) 打赏
未经允许不得转载PHP开源Hub » NodeJS:将文件夹按照存放路径变成一个对应的JSON

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

PHP开源Hub-致力于互联网开发者的成长

技术群聊软文发表

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏