Javascript fs.copy无法处理大量图像,只能处理少量图像
我有一个文件名数组,我正试图从一个目录复制到另一个目录。文件名在Javascript fs.copy无法处理大量图像,只能处理少量图像,javascript,node.js,file,asynchronous,Javascript,Node.js,File,Asynchronous,我有一个文件名数组,我正试图从一个目录复制到另一个目录。文件名在async系列链中的函数中构造,然后在最后一个函数中,使用fs.copy复制文件名。脚本也在十个不同的目录上运行,所以我看到的是这样的。它被简化了,但功能是相同的 var dirs = [{ 'src': 'dir1', 'dest': 'dest/dir1', 'files': [] }, { 'src': 'dir2', 'dest': 'dest/dir2', 'files':
async
系列
链中的函数中构造,然后在最后一个函数中,使用fs.copy
复制文件名。脚本也在十个不同的目录上运行,所以我看到的是这样的。它被简化了,但功能是相同的
var dirs = [{
'src': 'dir1',
'dest': 'dest/dir1',
'files': []
}, {
'src': 'dir2',
'dest': 'dest/dir2',
'files': []
}, {
'src': 'dir3',
'dest': 'dest/dir3',
'files': []
}, {
'src': 'dir4',
'dest': 'dest/dir4',
'files': []
}];
async.series([function(callback){
//get files
dirs.forEach(function(currentSrc){
fs.readdirSync(currentSrc);
});
callback();
},
function(callback){
//make dest dirs with dirs.forEach and fs.mkdir
callback();
},
function(callback){
var src
, dest;
dirs.forEach(funtion(dir){
dir.files.forEach(function(file){
src = path.join(dir.src, file);
dest = path.join(dir.dest, file);
fs.copy(src, dest, {replace: false}, function(err) {
if (err){
console.log('error copying file: ', err);
}
});
});
}]);
这对少量文件很好,但是当我尝试使用包含大约400MB的目录时,失败了。所有文件似乎都在目标中,但除了名称(正确的名称)之外还有do数据,但每个文件的文件大小都是0。为什么这适用于少量文件,但不适用于大型文件
更新。我得到了错误
events.js:85
投掷者;//未处理的“错误”事件
更新:
我现在使用@Jacob提供的策略,我得到的是:
var dirs = [{
'src': 'src/1',
'dest': 'waterfallDest1',
'files': []
}, {
'src': 'src/2',
'dest': 'waterfallDest2',
'files': []
}, {
'src': 'src/3',
'dest': 'waterfallDest3',
'files': []
}, {
'src': 'src/4',
'dest': 'waterfallDest4',
'files': []
}];
async.eachLimit(dirs, 1000, function (dir, cb) {
async.waterfall([
function (cb) {
fs.mkdir(dir.dest, cb);
},
function (cb) {
fs.readdir(dir.src, cb);
},
function (files, cb) {
async.eachLimit(files, 10, function (file, cb) {
var src = path.join(dir.src, file);
var dest = path.join(dir.dest, file);
try { // In case fs.copy is indeed throwing an error
fs.copy(src, dest, {replace: false}, cb);
} catch (err) {
cb('try-catch err ', err);
}
}, cb);
}
], cb);
}, function (err) {
if (err) {
console.log('Some error happened:\n' + err.stack);
}
});
这将成功创建所有目录,并成功地将文件传输到第一个目录中,但随后的每个目录中都充满了0k映像。您需要为
async.series
调用进行最终回调:
async.series([
function (callback) {
dirs.forEach(function (currentSrc) {
fs.readdirSync(currentSrc);
});
callback();
},
function (callback) {
//make dest dirs with dirs.forEach and fs.mkdir
callback();
},
function(callback) {
var src, dest;
dirs.forEach(funtion(dir){
dir.files.forEach(function(file){
src = path.join(dir.src, file);
dest = path.join(dir.dest, file);
fs.copy(src, dest, {replace: false}, function(err) {
if (err){
console.log('error copying file: ', err);
// Did you want to do callback(err)?
}
});
});
})
// Somewhere, this needs to call back.
}
], function (err, result) {
if (err) {
// One of the steps had an error; handle it.
}
});
下面是代码如何使用async.each
来避免所有这些循环。它还包括避免操作系统一次打开过多文件的限制:
async.eachLimit(dirs, 10, function (dir, cb) {
async.waterfall([
function (cb) {
fs.mkdir(dir.dest, cb);
},
function (cb) {
fs.readdir(dir.src, cb);
},
function (files, cb) {
async.eachLimit(files, 10, function (file, cb) {
var src = path.join(dir.src, file);
var dest = path.join(dir.dest, file);
try { // In case fs.copy is indeed throwing an error
fs.copy(src, dest, {replace: false}, cb);
} catch (err) {
cb(err);
}
}, cb);
}
], cb);
}, function (err) {
if (err) {
console.log('Some error happened:\n' + err.stack);
}
});
Per“您可以使用try/catch处理异常或允许异常冒泡。”
无论如何,底层库ncp应该为fs中的零星回调负责如果ncp幕后对单个文件多次调用回调,则第二次回调将引发异常,该异常。。。该文件已经存在。我很好奇,既然您已经在使用
async
,为什么要使用readdirSync
。@Jacob这可能是我之前使用过的东西的残余。我对这一切都很陌生。你建议我怎么做?可能1000的限制太多了,因为它是1000x10(并发文件)=10000个文件被并行复制。谢谢。“在某个地方需要回拨。”因为同步中的forEachforEach
,可能这就是问题所在。也许我可以用async.each
?如果是这样的话,回调会去哪里?我注意到您只是将cb
s作为参数传递给各种函数,但从不调用它们。这是故意的吗?在async.each
的情况下,async.failter
将调用回调。类似地,其他回调传递给异步函数,异步函数将负责调用它们。你只需要在其他事情还没有做的时候调用回调。我已经实现了你提供给我的瀑布式解决方案。谢谢但是,只有文件成功传输到第一个目录。在那之后,后续文件似乎在各自的dest
dir中,但只是名称。都是0公里。我已经用我目前掌握的信息更新了我的问题。您认为您可以再看一看吗?另外,这种方法是否不显式调用回调标准?在异步API上,在每个函数的末尾显式调用回调。谢谢。这个错误意味着什么?文件根本不存在?为什么不在cp
回调中处理呢?嗨。try-catch
块未产生任何错误。获取ENFILE时出错,请打开
,然后输入其中一个文件的名称。你知道那可能是什么吗?是否认为打开文件是cp
的一部分,而这是失败的。如果是这样,我的try-catch
没有捕获到它,这很奇怪。ENFILE
表示文件表溢出
;您可能同时打开了太多文件。有关使用eachLimit
避免太多并发任务的信息,请参阅我的更新。对于异步错误,try-catch不起作用。(即使是这样,简单地捕获错误并忽略它也不是正确的解决方案。)错误默认情况下,任何事件发射器上的事件都会引发异常-请参阅。如果您有权访问有问题的事件发射器,则可以通过设置错误处理程序来捕获它。但我不明白你怎么能做到,这在我看来似乎是fs
的一个缺点。Jacob的解决方案(async.eachLimit
)可能是下一个最好的解决方案。@Thomas哦,很好,您现在终于在ENFILE中遇到了一个有用的错误。正如Jacob所建议的,有一个打开的文件限制,您已经超过了它。节点的一个优点是它可以很好地扩展。节点的一个缺点是它可以触发多个可以达到这样极限的东西。
try {
fs.copy(src, dest, {replace: false});
} catch(e) {
if ( e.code != 'EEXIST' ) throw e; // I'm guessing here that this
// is your problem.
}