提问人:Abraham P 提问时间:6/19/2017 最后编辑:Jason AllerAbraham P 更新时间:8/6/2018 访问量:405
迭代目录的最有效方法是什么?
Which is the most efficient way to iterate a directory?
问:
假设我有一个目录foo,其中包含一定数量的子目录。这些子目录中的每一个都有 0 到 5 个可变长度的文件,我想处理这些文件。我的初始代码如下所示:
pool.query(`
SET SEARCH_PATH TO public,os_local;
`).then(() => fs.readdirSync(srcpath)
.filter(file => fs.lstatSync(path.join(srcpath, file)).isDirectory())
.map(dir => {
fs.access(`${srcpath + dir}/${dir}_Building.shp`, fs.constants.R_OK, (err) => {
if (!err) {
openShapeFile(`${srcpath + dir}/${dir}_Building.shp`).then((source) => source.read()
.then(function dbWrite (result) {
if (result.done) {
console.log(`done ${dir}`)
} else {
const query = `INSERT INTO os_local.buildings(geometry,
id,
featcode,
version)
VALUES(os_local.ST_GeomFromGeoJSON($1),
$2,
$3,
$4) ON CONFLICT (id) DO UPDATE SET
featcode=$3,
geometry=os_local.ST_GeomFromGeoJSON($1),
version=$4;`
return pool.connect().then(client => {
client.query(query, [geoJson.split('"[[').join('[[').split(']]"').join(']]'),
result.value.properties.ID,
result.value.properties.FEATCODE,
version
]).then((result) => {
return source.read().then(dbWrite)
}).catch((err) => {
console.log(err,
query,
geoJson.split('"[[').join('[[').split(']]"').join(']]'),
result.value.properties.ID,
result.value.properties.FEATCODE,
version
)
return source.read().then(dbWrite)
})
client.release()
})
}
})).catch(err => console.log('No Buildings', err))
}
})
fs.access(`${srcpath + dir}/${dir}__ImportantBuilding.shp`, fs.constants.R_OK, (err) => {
//read file one line at a time
//spin up connection in pg.pool, insert data
})
fs.access(`${srcpath + dir}/${dir}_Road.shp`, fs.constants.R_OK, (err) => {
//read file one line at a time
//spin up connection in pg.pool, insert data
})
fs.access(`${srcpath + dir}/${dir}_Glasshouse.shp`, fs.constants.R_OK, (err) => {
//read file one line at a time
//spin up connection in pg.pool, insert data
})
fs.access(`${srcpath + dir}/${dir}_RailwayStation.shp`, fs.constants.R_OK, (err) => {
//read file one line at a time
//spin up connection in pg.pool, insert data
})
})
这基本上是有效的,但它最终必须等待每个子目录中最长的文件被完全处理,导致在实践中总是只有 1 个与数据库的连接。
有没有办法重新构建它以更好地利用我的计算资源,同时限制活动 postgres 连接的数量并强制代码等到连接可用?(我在 node-postgres 的 pg poolConfig 中将它们设置为 20)
答:
-1赞
Nurik Nurmetov
6/19/2017
#1
如果您需要在一定时间内依次处理文件,则可以使用 Streams、timers(用于调度)和 process.nextTick()。 有很好的手册可以理解 nodejs 中的流。
-2赞
TxRegex
6/27/2017
#2
下面是使用生成器获取目录内容的示例。您可以立即开始获取前几个文件,然后使用异步代码并行处理文件。
// Dependencies
const fs = require('fs');
const path = require('path');
// The generator function (note the asterisk)
function* getFilesInDirectory(fullPath, recursive = false) {
// Convert file names to full paths
let contents = fs.readdirSync(fullPath).map(file => {
return path.join(fullPath, file);
});
for(let i = 0; i < contents.length; i++) {
const childPath = contents[i];
let stats = fs.statSync(childPath);
if (stats.isFile()) {
yield childPath;
} else if (stats.isDirectory() && recursive) {
yield* getFilesInDirectory(childPath, true);
}
}
}
用法:
function handleResults(results) {
... // Returns a promise
}
function processFile(file) {
... // Returns a promise
}
var files = getFilesInDirectory(__dirname, true);
var result = files.next();
var promises = [];
while(!result.done) {
console.log(result.value);
file = files.next();
// Process files in parallel
var promise = processFile(file).then(handleResults);
promises.push(promise);
}
promise.all(promises).then() {
console.log(done);
}
评论
4赞
Bergi
6/27/2017
使用生成器并不能真正帮助并行处理文件。
1赞
Bergi
6/27/2017
那个丑陋的循环应该是一个简单的.while(1)
yield* getFilesInDirectory(childPath, true);
0赞
TxRegex
6/28/2017
@Bergi - 已修复。谢谢!
评论