NodeJS copyFile затем отсоединить в обратном вызове - PullRequest
0 голосов
/ 08 ноября 2018

У меня есть большое количество файлов (миллионов), которые я хочу скопировать из папки в другую, но затем, основываясь на некоторых параметрах синтаксического анализа, мне нужно будет удалить файл, если он не соответствует некоторым критериям.

Я выполняю синтаксический анализ моей локальной копии файла, потому что в сети он будет медленнее разбирать (читать файл + разбирать), чем делать это локально.

Мой код выглядит так:

for (let file of files) {
    fs.copyFile(from, to, err => {
        if (err) return;
        parse(file);
   });
}

Функция parse выглядит примерно так:

parse = file => {
    fs.readFile(file, (err, data) => {
        //do some parsing
        if (notOk) {
            fs.unlink(file);
        };
    }
}

Проблема в том, что он выполняет все copyFile и, похоже, не выполняет обратный вызов с unlink, и мне действительно нужно отменить связь, как только файл закончит копирование, так как я не могу себе позволить дисковое пространство, чтобы сначала скопировать все файлы.

Нужно ли использовать Sync версию этих методов или что-то еще?

Спасибо

Я бы ожидал такой вывод:

copyFile a
copyFile b
copyFile c
parsing a
copyFile d
unlink a
parsing b
copyFile e
...

но вместо этого у меня есть все copyFile, и ничего из этого не происходит.

Ответы [ 2 ]

0 голосов
/ 08 ноября 2018

Если files содержит миллионы файлов, вы запускаете миллионы одновременных операций копирования, что, вероятно, перегружает вашу систему.

Вместо этого попробуйте использовать что-то вроде async.eachLimit, чтобы ограничить количество одновременных операций копирования.

Не проверенный пример:

const async = require('async');

async.eachLimit(files, 10, (file, callback) => {
  fs.copyFile(from, to, err => {
    if (err) return callback(); // or pass `err`
    parse(file, callback);
  });
});

function parse(file, callback) {
  fs.readFile(file, (err, data) => {
    //do some parsing
    if (notOk) {
      fs.unlink(file, callback);
    } else {
      return callback();
    }
  })
}
0 голосов
/ 08 ноября 2018

Я думаю, что это происходит, обратный вызов в копировании завершается, поэтому поток завершается, но функции не могут завершиться, вы можете выполнить эту синхронизацию, и она будет работать нормально и будет более понятной, но другой способ - это преобразуйте функции в обещания, чтобы вы могли вернуть обещание и ждать их.

Вы могли бы написать что-то вроде этого.

const util = require('util');
const fs = require('fs'); 
const files = ['1.txt', '2.txt', '3.txt', '4.txt'];
//promisify all the fs functions to use.
const copyFilePromise = util.promisify(fs.copyFile); 
const readFilePromise = util.promisify(fs.readFile); 
const unlinkPromise = util.promisify(fs.unlink);

//make a parser function that return a promise.
const parse = (file) => {
    return readFilePromise(file) 
            .then(() => { 
                //do some parsing 
                if(notOk) 
                    return unlinkPromise(file)
    });
};

//store all the promises in an array
let promises = []

//iterate for all the files using the promisify aproach of the functions
for (let file of files){
    //add all the promises to an array of promises.
    promises.push(copyFilePromise(from, to).then(parse(file)).catch(console.error));
}

//wait for all the promises to resolve.
Promise.all(promises);
...