fs.大量图像复制失败,少量图像复制有效

fs.copy fails with large number of images, works for small number

本文关键字:图像 复制 有效 失败 fs      更新时间:2023-09-26

我有一个文件名数组,我试图将其从一个目录复制到另一个目录。在async - series链内的函数中构造文件名,然后在最后的函数中使用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的目录时,它失败了。所有的文件看起来都在目标中,但是除了名称之外没有任何数据(这些名称是正确的),但是每个文件的文件大小都是0。为什么这种方法只适用于少量文件,而不适用于大型文件?

更新。我得到错误

events.js: 85把呃;//未处理的'error'事件

更新:我现在使用的是@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图像。

根据文档"您可以使用try/catch来处理异常或允许它们冒泡。"

  try {
    fs.copy(src, dest, {replace: false});
  } catch(e) {
    if ( e.code != 'EEXIST' ) throw e; // I'm guessing here that this
                                       // is your problem.
  }

不管它的价值是什么,底层库ncp是fs中零星回调的罪魁祸首。如果 ncp在后台为一个文件调用了不止一次的回调,那么第二次回调将抛出一个异常…文件已经存在

您需要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);
  }
});