Как избежать ошибки по ограничению открытых файлов?
Здравствуйте. Подскажите пожалуйста. Недавно я писал на этом форуме с вопросом, о том, как создать структуру файлов и попок из исходного каталога в другом каталоге
https://javascript.ru/forum/node-js-...j-sisteme.html Для копирование структуры я нашел и доработал под себя вот такую функцию: function walkSync (dir, filelist = []) { fs.readdirSync(dir).forEach(file => { const dirFile = path.join(dir, file); replaceDirPath = dir.replace("sources\\products\\", replaceDir + value + "/"); if(!fs.existsSync(replaceDirPath)){ fs.mkdirSync(replaceDirPath); } try { filelist = walkSync(dirFile, filelist); } catch (err) { if (err.code === 'ENOTDIR' || err.code === 'EBUSY') filelist = [...filelist, dirFile]; else throw err; } }); В цикле получаем пути папок в переменной dir, далее меняем в ней путь на нужный (что бы создать данную структуру в другом каталоге) и записываем в replaceDirPath, тут же и создаем каталоги по пути replaceDirPath. Второй момент - мне необходимо кроме того, что создать структуру в другом каталоге, так еще и вложить всю эту структуру в несколько каталогов - у меня это разные размеры фотографий. Что бы было понятнее, я объясню задачу вообще, что именно я хочу: Есть папка с исходными фотографиями, со своей структурой, из это папки нужно сделать несколько папок-копий, но фотографии в каждой из папок будут иметь разный размер, то есть выходит такая структура: Цитата:
Цитата:
// Размеры картинок var settings = { '400x400':'400, 400' //КАРТОЧКА ТОВАРА: Основная фотография ,'80x80':'80, 80' //КАРТОЧКА ТОВАРА: сопутсвующий товар ,'200x200':'200, 200' //КАРТОЧКА ТОВАРА: хит продаж ,'120x120':'120, 120' //КАТЕГОРИИ: может пригодиться ,'265x265':'265, 265' //КАТЕГОРИИ: Фото позици ,'190x190':'190, 190' //КАТЕГОРИИ: хит продаж ,'175x175':'175, 175' //ОБЩИЕ: просмотренные }; Далее я переделал первую функцию, walkSync() так, что бы она в структуре сразу же создала и папки 400x400, 80x80, 200x200 и т.д. Для этого в функцию я добавил цикл для объекта settings: function walkSync (dir, filelist = []) { fs.readdirSync(dir).forEach(file => { const dirFile = path.join(dir, file); for(value in settings){ if(!fs.existsSync("./products/" + value + "/")){ fs.mkdirSync("./products/" + value + "/"); } replaceDirPath = dir.replace("sources\\products\\", replaceDir + value + "/"); if(!fs.existsSync(replaceDirPath)){ fs.mkdirSync(replaceDirPath); } } try { filelist = walkSync(dirFile, filelist); } catch (err) { if (err.code === 'ENOTDIR' || err.code === 'EBUSY') filelist = [...filelist, dirFile]; else throw err; } }); Теперь эта функция полностью создала мне нужную структуру. Далее я пробую по этой структуре раскидать копии файлов из исходников Для этого результат работы функции, массив, я принимаю в переменную list и прохожусь по нему циклом, копируя файлы по папкам из исходного каталога var list = walkSync(dir); list.forEach(function (v) { var dest = v, target = v.replace("sources\\products\\", replaceDir); fs.copyFile(dest, target, 0,(err)=>{ if(err) console.log(err); }); }); Все работает как нужно, копии раскидались по нужным папкам. Теперь пришло время основной задачи - обработка фотографий, для этого используется модуль jimp Теперь, вместо копирования (fs.copyFile) я пользуюсь модулем jimp, ему нужно указать откуда берем файл и куда кладем - то есть по сути он сам занимается копированием, делаю функцию обработки фото: function renderImg(dest, target){ jimp.read(dest, (err, img) => { if (err) throw err; img //.resize() // resize //.quality(60) // set JPEG quality //.greyscale() .write(target); // save }); } и добавляю ее в цикл, вместо функции копирования, теперь цикл выглядит так: //Цикл обработки и размещения файлов list.forEach(function (v) { var dest = v; for(value in settings){ var target = v.replace("sources\\products\\", replaceDir + value + "\\"); renderImg(dest, target); //Обработка файлов и копирование } }); Но тут я и получаю ошибку "Error: EMFILE: too many open files" Как я понимаю jimp долго обрабатывает каждый файл и не успевает выполнить то, что ему дает цикл, таким образом открытых файлов становиться больше, чем можно, в моем случае это 256. Фотографий в исходной папке около 1700 на данный момент, но они еще и умножаться на количество папок-размеров, то есть больше 10к. Подскажите пожалуйста, как можно избежать такой проблемы? Опыта у меня мало, чувствую, что код написан коряво, но я это писал несколько дней, уже не знаю куда и смотреть. Возможно, как-то можно тормозить цикл и возбуждать его по событию или как-то вообще все по другому сделать? Буду рад любому пояснению |
Вот мой код целиком
var fs = require('fs') ,path = require('path') ,jimp = require('jimp') // Настройки var dir = "sources/products", replaceDirPath= "", replaceDir = "./products/"; // Название папок и размеры картинок var settings = { '400x400':'400, 400' //КАРТОЧКА ТОВАРА: Основная фотография ,'80x80':'80, 80' //КАРТОЧКА ТОВАРА: сопутсвующий товар ,'200x200':'200, 200' //КАРТОЧКА ТОВАРА: хит продаж ,'120x120':'120, 120' //КАТЕГОРИИ: может пригодиться ,'265x265':'265, 265' //КАТЕГОРИИ: Фото позици ,'190x190':'190, 190' //КАТЕГОРИИ: хит продаж ,'175x175':'175, 175' //ОБЩИЕ: просмотренные }; // Обработка картинок-файлов function renderImg(dest, target){ jimp.read(dest, (err, img) => { if (err) throw err; img //.resize() // resize //.quality(60) // set JPEG quality //.greyscale() .write(target); // save }); } function walkSync (dir, filelist = []) { fs.readdirSync(dir).forEach(file => { const dirFile = path.join(dir, file); for(value in settings){ if(!fs.existsSync("./products/" + value + "/")){ fs.mkdirSync("./products/" + value + "/"); } replaceDirPath = dir.replace("sources\\products\\", replaceDir + value + "/"); if(!fs.existsSync(replaceDirPath)){ fs.mkdirSync(replaceDirPath); } } try { filelist = walkSync(dirFile, filelist); } catch (err) { if (err.code === 'ENOTDIR' || err.code === 'EBUSY') filelist = [...filelist, dirFile]; else throw err; } }); return filelist; } var list = walkSync(dir); //Цикл обработки и размещения файлов list.forEach(function (v) { var dest = v; for(value in settings){ var target = v.replace("sources\\products\\", replaceDir + value + "\\"); renderImg(dest, target); // fs.copyFile(dest, target, 0,(err)=>{ // if(err) console.log(err); // }); } }); |
Не получилось у вас убежать от асинхронности:)
Делать придётся примерно так: function renderImg(dest, target){ return jimp.read(dest).then(img => { return img.write(target) }); }; function oneByOne(array, func, errorCallback) { return array.reduce((p, arguments)=> p.then( result => func.apply(this, arguments), error => { if(errorCallback) errorCallback(error); return func.apply(this, arguments); }, ), Promise.resolve()); }; var argumentsList = list.reduce((array, dest) => { for(value in settings){ array.push([ dest, dest.replace("sources\\products\\", replaceDir + value + "\\") ]) } }, []); oneByOne(argumentsList, renderImg); |
Цитата:
|
Часовой пояс GMT +3, время: 07:34. |