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


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

У меня есть каталог с html-файлами, которые я хочу отправить обратно клиенту в объектных кусках с узлом.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});

окончательный обратный вызов также неверен. Он должен быть вызван, когда все файлы в каталоге будут сделаны.

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

7   51   2012-04-07 01:38:22

7 ответов:

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

вот часть чтения:

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 функции или использовать обещания. Асинхронные обратные вызовы-это не очень хороший стиль.

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

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

/**
 * 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 );
});

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

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 );
    });
});

как это Работает

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

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);

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

читать:

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;
});

вы ленивый человек, как я и люблю НПМ модуль: 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 
   });    

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

  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);
  });
const FS = require('fs');
const PATH = require('path');

function readFiles(dirPath, processFile) {
  // read directory
  FS.readdir(dirPath, (err, fileNames) => {
    if (err) throw err;
    // loop through files
    fileNames.forEach((fileName) => {
      // get current file name
      let name = PATH.parse(fileName).name;
      // get current file extension
      let ext = PATH.parse(fileName).ext;
      // get current file path
      let path = PATH.resolve(dirPath, fileName);
      // callback, do something with the file
      processFile(name, ext, path);
    });
  });
}

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

readFiles('path/to/directory', (name, ext, path) => {
  console.log(`file name is: ${name}`);
  console.log(`file extension is: ${ext}`);
  console.log(`file path is: ${path}`);
}

другая версия с современным методом 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));