在编程之前,一定要有一个信条:代码是为了减少工作量而生的,重复枯燥的工作是不能容忍的。
需求
这是由上篇文章衍生出的需求,我已经将一个文件夹内所有的文件名转译为英文,但我在页面上还需要将这些图片引入加载。如果一个一个手写到程序里,未免有点劳心劳神。那么何不将这个文件夹按照存放路径变成一个相应的JSON在前端请求并渲染呢?
说干就干。
文件夹的路径如下所示:
一级路径:test
二级路径:A,B,C...共十三个文件夹
三级路径:每个二级路径下有3-8个文件夹不等
四级路径:a.jpg,b.jpg,c.jpg等数量不等的图片文件
思路
1.一个全局变量:数组类型obj。
2.递归遍历目录,是文件夹的取出名字,建立一个对象,放入文件夹名name和一个空数组list,如
1 2 3 4 | {
name: ‘fileName‘ ,
list:[] //用来存放下属路径 } |
3.依次重复步骤2,直至寻找到路径下的文件,将文件名name和拼合好的路径src放入归属的list中,如下:
1 2 3 4 5 6 | list:[
{
name: ‘fileName‘ ,
src: ‘filePath‘
} ] |
实践
语言
NodeJS
需求模块
fs/async。
代码 先上代码,逻辑解析在提示补上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | ( 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模块的理由。
在引入模块之后,第一步要着眼于判断为文件夹后的函数:
1 2 3 4 5 6 7 | //如果obj为空,说明我们是第一次进入函数,那么插入一个新的元素 if (obj.length <= 0) {
obj.push({
name: path,
list: []
}) } |
async.forEachLimit是异步串行函数,可以同批次运行指定数量的代码,可以避免一次遍历太多,里面的参数依次为(数组,指定的数量,执行函数,错误回调)。
下面代码中的参数很多,如paths,path,src,_src等,打代码的时候经常会让我头脑不清晰,这也侧面告诫了我一个问题,同一作用域内不宜有太多处理函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | //如果路径参数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时可以将首行的去重方法删除,看看效果。
处理好了文件夹状态下的方法,来看看已经到了四级路径的处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //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], 知识推荐
我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8
不良信息举报平台
互联网安全管理备案
Copyright 2023 www.wodecom.cn All Rights Reserved |