前言
现在需要实现这样一个功能,将目录a中所有文件及文件夹复制到目录b,并在整个操作完成后,执行一次某个方法,或者一个回调。
有几种方法可以尝试实现上述功能
-
遍历目录及文件前,给个计数器,初始值设置在null,文件/目录每读取一个文件,计数器数量增加1(若初始值为null,则直接赋值1),复制完成后数量减少1,每隔某个时间后读取计数器,若计数器不是null并且是0,则表示已经复制完成,调用回调方法。
这种方法 计数可能会不准
-
遍历目录中都使用同步的方法,nodejs中fs库大部分方法都有同步的实现,比如说fs.stat有fs.statSync。在复制完成后执行回调。
这种方法可能会耗时过长,代码阻塞
另一种方法是使用fs的同步方法+promise.all,同步读取目录,异步处理文件复制,promise.all回调来执行复制文件完成的回调
// copyfile.js
const path = require('path')
const fs = require('fs')
module.exports = function (fromDir, toDir) {
if (!fromDir || !toDir || fromDir == toDir) {
return Promise.reject(new Error(`参数无效:${fromDir} - ${toDir}`))
}
return new Promise((resolve, reject) => {
!fs.existsSync(toDir) && fs.mkdirSync(toDir, {recursive: true})
const task = []
readFileSync(fromDir, toDir, (fromFullPath, toFullPath, stat) => {
task.push({
fromFullPath, toFullPath, stat
})
})
Promise.all(task.map(k => loopCopyFilePromise(k))).then(resolve).catch(e => reject(e))
})
}
function readFileSync(fromDir, toDir, cb) {
const method = arguments.callee;
const fileList = fs.readdirSync(fromDir)
fileList.forEach((name) => {
const fromFullPath = path.join(fromDir, name)
const toFullPath = path.join(toDir, name)
const stat = fs.statSync(fromFullPath)
if (stat.isDirectory()) {
!fs.existsSync(toFullPath) && fs.mkdirSync(toFullPath, {recursive: true})
method(fromFullPath, toFullPath, cb)
}
if (stat.isFile()) {
cb(fromFullPath, toFullPath, stat)
}
})
}
function loopCopyFilePromise(args) {
const {fromFullPath, toFullPath, stat} = args
if (stat.size > 10000) {
return new Promise((resolve, reject) => {
const readStream = fs.createReadStream(fromFullPath),
writeStream = fs.createWriteStream(toFullPath)
readStream.pipe(writeStream)
writeStream.on('finish', resolve)
writeStream.on('error', reject)
})
} else {
return new Promise((resolve, reject) => {
fs.copyFile(fromFullPath, toFullPath, (err) => {
err ? reject() : resolve();
});
})
}
}
模块返回一个promise,可以直接在then方法加回调
const copyfile = require("。/filecopy")
console.log('start...')
copyfile("./dirA",'./dirB').then(()=>{
console.log("这里执行回调")
console.log("end...")
})
有时候会有这样的使用场景,从远程上下载文件到某个临时目录,然后复制到某个指定的目录,最后删除临时目录,此时就需要在文件复制完成后,执行清理工作