Avatar ·

Как получить список всех файлов в папке с помощью Node.js?

Привет всем! Я новичок в Node.js и пишу небольшой скрипт для обработки изображений. Мне нужно получить список всех файлов в определённой папке, чтобы потом пройтись по ним циклом и выполнить какие-то действия (например, изменить размер или переименовать). Я пробовал использовать `fs.readdir`, но у меня не получается. Вот мой код: ```javascript const fs = require('fs'); const folderPath = './images'; const files = fs.readdir(folderPath); console.log(files); // Выводит undefined ``` Я ожидал увидеть массив с именами файлов, но получаю `undefined`. Я читал, что `fs.readdir` асинхронный, но не совсем понимаю, как правильно с ним работать. Может быть, нужно использовать колбэк или промисы? Также интересует, как отфильтровать только файлы, исключив папки, и как получить список файлов с полным путём. И ещё: есть ли способ сделать это синхронно, чтобы код был проще для понимания? Буду благодарен за подробное объяснение с примерами кода. Заранее спасибо! <<>>

Проблема и её решение

Ваш код не работает, потому что fs.readdir — асинхронная функция. Она не возвращает результат напрямую, а принимает колбэк или возвращает промис (в версиях Node.js 10+). Когда вы пытаетесь присвоить результат переменной files, вы получаете undefined, так как операция ещё не завершилась.

Вот три основных способа получить список файлов:

1. Асинхронный метод с колбэком (классический)

const fs = require('fs');
const path = require('path');

const folderPath = './images';

fs.readdir(folderPath, (err, files) => {
  if (err) {
    console.error('Ошибка чтения папки:', err);
    return;
  }
  
  console.log('Все содержимое папки:', files);
  
  // Фильтруем только файлы (исключаем папки)
  const onlyFiles = files.filter(file => {
    const fullPath = path.join(folderPath, file);
    return fs.statSync(fullPath).isFile();
  });
  
  console.log('Только файлы:', onlyFiles);
  
  // Добавляем полный путь
  const filesWithPath = onlyFiles.map(file => path.join(folderPath, file));
  console.log('Файлы с полным путём:', filesWithPath);
});

2. Асинхронный метод с промисами (современный)

const fs = require('fs').promises;
const path = require('path');

async function listFiles(folderPath) {
  try {
    const items = await fs.readdir(folderPath);
    console.log('Все содержимое папки:', items);
    
    // Фильтруем только файлы
    const files = [];
    for (const item of items) {
      const fullPath = path.join(folderPath, item);
      const stat = await fs.stat(fullPath);
      if (stat.isFile()) {
        files.push(item);
      }
    }
    
    console.log('Только файлы:', files);
    
    // С полным путём
    const filesWithPath = files.map(file => path.join(folderPath, file));
    console.log('Файлы с полным путём:', filesWithPath);
    
    return filesWithPath;
  } catch (err) {
    console.error('Ошибка:', err);
  }
}

// Использование
listFiles('./images').then(files => {
  console.log('Получено файлов:', files.length);
});

3. Синхронный метод (простой, но блокирующий)

const fs = require('fs');
const path = require('path');

const folderPath = './images';

try {
  const items = fs.readdirSync(folderPath);
  console.log('Все содержимое папки:', items);
  
  // Фильтруем только файлы
  const onlyFiles = items.filter(item => {
    const fullPath = path.join(folderPath, item);
    return fs.statSync(fullPath).isFile();
  });
  
  console.log('Только файлы:', onlyFiles);
  
  // С полным путём
  const filesWithPath = onlyFiles.map(file => path.join(folderPath, file));
  console.log('Файлы с полным путём:', filesWithPath);
  
  // Дальше можно работать с массивом
  filesWithPath.forEach(file => {
    console.log('Обрабатываю:', file);
  });
  
} catch (err) {
  console.error('Ошибка:', err);
}

Рекомендации

  • Для небольших скриптов — используйте readdirSync, это проще и понятнее новичкам.
  • Для production-кода — используйте асинхронные методы с промисами (fs.promises.readdir), чтобы не блокировать event loop.
  • Всегда проверяйте ошибки — папка может не существовать, файлы могут быть заблокированы и т.д.
  • Используйте path.join для корректного формирования путей (это работает на Windows, Linux и macOS).

Теперь ваш код будет работать правильно!

<<>>

Альтернативный подход: использование рекурсии для вложенных папок

Если вам нужно получить список всех файлов не только в одной папке, но и во всех вложенных подпапках, можно написать рекурсивную функцию:

const fs = require('fs').promises;
const path = require('path');

async function getAllFiles(dir) {
  const items = await fs.readdir(dir, { withFileTypes: true });
  const files = [];
  
  for (const item of items) {
    const fullPath = path.join(dir, item.name);
    if (item.isDirectory()) {
      // Рекурсивно заходим в подпапку
      const subFiles = await getAllFiles(fullPath);
      files.push(...subFiles);
    } else if (item.isFile()) {
      files.push(fullPath);
    }
  }
  
  return files;
}

// Использование
getAllFiles('./images').then(files => {
  console.log('Все файлы (включая вложенные):', files);
});

Обратите внимание на опцию { withFileTypes: true } — она возвращает объекты fs.Dirent, у которых есть методы isFile() и isDirectory(). Это избавляет от необходимости вызывать fs.stat для каждого элемента, что значительно ускоряет работу с большими папками.

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