Подтвердить что ты не робот

Чтение всех файлов в каталоге, сохранение их в объектах и ​​отправка объекта

Я не знаю, возможно ли это, но здесь. И работа с обратными вызовами делает его еще более трудным.

У меня есть каталог с html файлами, который я хочу отправить клиенту в Object Chunk с помощью node.js и socket.io.

Все мои файлы находятся в /tmpl

Итак, сокет должен прочитать все файлы в /tmpl.

для каждого файла он должен хранить данные в объекте с именем файла в качестве ключа, а содержимое - значением.

  var data;
  // this is wrong because it has to loop trough all files.
  fs.readFile(__dirname + '/tmpl/filename.html', 'utf8', function(err, html){
      if(err) throw err;
      //filename must be without .html at the end
      data['filename'] = html;
  });
  socket.emit('init', {data: data});

Последний ответ также неверен. Он должен вызываться, когда все файлы в каталоге выполнены.

Но я не знаю, как создать код, кто-нибудь знает, возможно ли это?

4b9b3361

Ответ 1

Итак, есть три части. Чтение, хранение и отправка.

Здесь часть чтения:

var fs = require('fs');

function readFiles(dirname, onFileContent, onError) {
  fs.readdir(dirname, function(err, filenames) {
    if (err) {
      onError(err);
      return;
    }
    filenames.forEach(function(filename) {
      fs.readFile(dirname + filename, 'utf-8', function(err, content) {
        if (err) {
          onError(err);
          return;
        }
        onFileContent(filename, content);
      });
    });
  });
}

Здесь хранящаяся часть:

var data = {};
readFiles('dirname/', function(filename, content) {
  data[filename] = content;
}, function(err) {
  throw err;
});

Отправляющая часть зависит от вас. Вы можете отправить их по одному или после прочтения.

Если вы хотите отправлять файлы после завершения чтения, вы должны либо использовать версии синхронизации функций fs, либо использовать promises. Асинхронные обратные вызовы не являются хорошим стилем.

Кроме того, вы спрашивали об отмене расширения. Вы должны задавать вопросы один за другим. Никто не напишет полное решение только для вас.

Ответ 2

Это современная версия Promise предыдущей, используя подход Promise.all для разрешения всех promises, когда все файлы были прочитаны:

/**
 * Promise all
 * @author Loreto Parisi (loretoparisi at gmail dot com)
 */
function promiseAllP(items, block) {
    var promises = [];
    items.forEach(function(item,index) {
        promises.push( function(item,i) {
            return new Promise(function(resolve, reject) {
                return block.apply(this,[item,index,resolve,reject]);
            });
        }(item,index))
    });
    return Promise.all(promises);
} //promiseAll

/**
 * read files
 * @param dirname string
 * @return Promise
 * @author Loreto Parisi (loretoparisi at gmail dot com)
 * @see http://stackoverflow.com/questions/10049557/reading-all-files-in-a-directory-store-them-in-objects-and-send-the-object
 */
function readFiles(dirname) {
    return new Promise((resolve, reject) => {
        fs.readdir(dirname, function(err, filenames) {
            if (err) return reject(err);
            promiseAllP(filenames,
            (filename,index,resolve,reject) =>  {
                fs.readFile(path.resolve(dirname, filename), 'utf-8', function(err, content) {
                    if (err) return reject(err);
                    return resolve({filename: filename, contents: content});
                });
            })
            .then(results => {
                return resolve(results);
            })
            .catch(error => {
                return reject(error);
            });
        });
  });
}

Как использовать его:

Так же просто, как делать:

readFiles( EMAIL_ROOT + '/' + folder)
.then(files => {
    console.log( "loaded ", files.length );
    files.forEach( (item, index) => {
        console.log( "item",index, "size ", item.contents.length);
    });
})
.catch( error => {
    console.log( error );
});

Предположим, что у вас есть еще один список папок, которые вы также можете перебирать по этому списку, так как внутреннее обещание. all будет решать каждый асинхронно:

var folders=['spam','ham'];
folders.forEach( folder => {
    readFiles( EMAIL_ROOT + '/' + folder)
    .then(files => {
        console.log( "loaded ", files.length );
        files.forEach( (item, index) => {
            console.log( "item",index, "size ", item.contents.length);
        });
    })
    .catch( error => {
        console.log( error );
    });
});

Как это работает

promiseAll делает магию. Он принимает функциональный блок подписи function(item,index,resolve,reject), где item - текущий элемент массива, index его позиция в массиве и resolve и reject функции обратного вызова Promise. Каждое обещание будет помещено в массив в текущем index и с текущим item в качестве аргументов через анонимный вызов функции:

promises.push( function(item,i) {
        return new Promise(function(resolve, reject) {
            return block.apply(this,[item,index,resolve,reject]);
        });
    }(item,index))

Затем все promises будут разрешены:

return Promise.all(promises);

Ответ 3

Для всех приведенных ниже примеров вам необходимо импортировать модули fs и path :

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

Асинхронное чтение файлов

function readFiles(dir, processFile) {
  // read directory
  fs.readdir(dir, (error, fileNames) => {
    if (error) throw error;

    fileNames.forEach(filename => {
      // get current file name
      const name = path.parse(filename).name;
      // get current file extension
      const ext = path.parse(filename).ext;
      // get current file path
      const filepath = path.resolve(dir, filename);

      // get information about the file
      fs.stat(filepath, function(error, stat) {
        if (error) throw error;

        // check if the current path is a file or a folder
        const isFile = stat.isFile();

        // exclude folders
        if (isFile) {
          // callback, do something with the file
          processFile(filepath, name, ext, stat);
        }
      });
    });
  });
}

Использование:

// use an absolute path to the folder where files are located
readFiles('absolute/path/to/directory/', (filepath, name, ext, stat) => {
  console.log('file path:', filepath);
  console.log('file name:', name);
  console.log('file extension:', ext);
  console.log('file information:', stat);
});

Чтение файлов синхронно, сохранение в массиве, естественная сортировка

/**
 * @description Read files synchronously from a folder, with natural sorting
 * @param {String} dir Absolute path to directory
 * @returns {Object[]} List of object, each object represent a file
 * structured like so: '{ filepath, name, ext, stat }'
 */
function readFilesSync(dir) {
  const files = [];

  fs.readdirSync(dir).forEach(filename => {
    const name = path.parse(filename).name;
    const ext = path.parse(filename).ext;
    const filepath = path.resolve(dir, filename);
    const stat = fs.statSync(filepath);
    const isFile = stat.isFile();

    if (isFile) files.push({ filepath, name, ext, stat });
  });

  files.sort((a, b) => {
    // natural sort alphanumeric strings
    // https://stackoverflow.com/a/38641281
    return a.name.localeCompare(b.name, undefined, { numeric: true, sensitivity: 'base' });
  });

  return files;
}

Использование:

// return an array list of objects
// each object represent a file
const files = readFilesSync('absolute/path/to/directory/');

Асинхронное чтение файлов с использованием обещания

Подробнее о обещании в этой статье.

const { promisify } = require('util');

const readdir_promise = promisify(fs.readdir);
const stat_promise = promisify(fs.stat);

function readFilesAsync(dir) {
  return readdir_promise(dir, { encoding: 'utf8' })
    .then(filenames => {
      const files = getFiles(dir, filenames);

      return Promise.all(files);
    })
    .catch(err => console.error(err));
}

function getFiles(dir, filenames) {
  return filenames.map(filename => {
    const name = path.parse(filename).name;
    const ext = path.parse(filename).ext;
    const filepath = path.resolve(dir, filename);

    return stat({ name, ext, filepath });
  });
}

function stat({ name, ext, filepath }) {
  return stat_promise(filepath)
    .then(stat => {
      const isFile = stat.isFile();

      if (isFile) return { name, ext, filepath, stat };
    })
    .catch(err => console.error(err));
}

Использование:

readFiles('absolute/path/to/directory/')
  // return an array list of objects
  // each object is a file
  // with those properties: { name, ext, filepath, stat }
  .then(files => console.log(files))
  .catch(err => console.log(err));

Примечание: верните undefined для папок, если хотите, вы можете отфильтровать их:

readFiles('absolute/path/to/directory/')
  .then(files => files.filter(file => file !== undefined))
  .catch(err => console.log(err));

Ответ 4

Вы ленивый человек, как я и любите модуль npm: D, проверьте это.

npm install node-dir

пример для чтения файлов:

var dir = require('node-dir');

dir.readFiles(__dirname,
    function(err, content, next) {
        if (err) throw err;
        console.log('content:', content);  // get content of files
        next();
    },
    function(err, files){
        if (err) throw err;
        console.log('finished reading files:', files); // get filepath 
   });    

Ответ 5

Другая версия с современным методом Promise. Это короче, чем другие ответы, основанные на обещании:

const readFiles = (dirname) => {

  const readDirPr = new Promise( (resolve, reject) => {
    fs.readdir(dirname, 
      (err, filenames) => (err) ? reject(err) : resolve(filenames))
  });

  return readDirPr.then( filenames => Promise.all(filenames.map((filename) => {
      return new Promise ( (resolve, reject) => {
        fs.readFile(dirname + filename, 'utf-8',
          (err, content) => (err) ? reject(err) : resolve(content));
      })
    })).catch( error => Promise.reject(error)))
};

readFiles(sourceFolder)
  .then( allContents => {

    // handle success treatment

  }, error => console.log(error));

Ответ 6

Если у вас есть Node.js 8 или новее, вы можете использовать новый util.promisify. (Я отмечаю как необязательные части кода, которые связаны с переформатированием в качестве объекта, который запрашивал исходный пост.)

  const fs = require('fs');
  const { promisify } = require('util');

  let files; // optional
  promisify(fs.readdir)(directory).then((filenames) => {
    files = filenames; // optional
    return Promise.all(filenames.map((filename) => {
      return promisify(fs.readFile)(directory + filename, {encoding: 'utf8'});
    }));
  }).then((strArr) => {
    // optional:
    const data = {};
    strArr.forEach((str, i) => {
      data[files[i]] = str;
    });
    // send data here
  }).catch((err) => {
    console.log(err);
  });

Ответ 7

Для того, чтобы код работал сглаженно в разных средах, path.resolve можно использовать в местах, где используется путь. Вот код, который работает лучше.

Часть чтения:

var fs = require('fs');

function readFiles(dirname, onFileContent, onError) {
  fs.readdir(dirname, function(err, filenames) {
    if (err) {
      onError(err);
      return;
    }
    filenames.forEach(function(filename) {
      fs.readFile(path.resolve(dirname, filename), 'utf-8', function(err, content) {
        if (err) {
          onError(err);
          return;
        }
        onFileContent(filename, content);
      });
    });
  });
}

Хранение:

var data = {};
readFiles(path.resolve(__dirname, 'dirname/'), function(filename, content) {
  data[filename] = content;
}, function(error) {
  throw err;
});