Node.js 读取目录中的所有文件,将它们存储在对象中,然后发送对象

Node.js 读取目录中的所有文件,将它们存储在对象中,然后发送对象,node.js,Node.js,我不知道这是否可能,但事情是这样的。而使用回调会让它变得更加困难 我有一个包含html文件的目录,我想用node.js和socket.io将这些文件以对象块的形式发送回客户端 我的所有文件都在/tmpl中 所以套接字需要读取/tmpl中的所有文件 对于每个文件,它必须将数据存储在一个对象中,文件名作为键,内容作为值 var data; // this is wrong because it has to loop trough all files. fs.readFile(__dir

我不知道这是否可能,但事情是这样的。而使用回调会让它变得更加困难

我有一个包含html文件的目录,我想用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});
最后的回调也是错误的。当目录中的所有文件都完成时,必须调用它


但是我不知道如何创建代码,有人知道这是否可行吗?

因此,有三个部分。读取、存储和发送

以下是阅读部分:

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 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('dirname/', function(filename, content) {
  data[filename] = content;
}, function(err) {
  throw err;
});
var data = {};
readFiles(path.resolve(__dirname, 'dirname/'), function(filename, content) {
  data[filename] = content;
}, function(error) {
  throw err;
});
发送部分由您决定。您可能希望一个接一个地发送,或者在阅读完成后发送

如果要在读取完成后发送文件,则应使用同步版本的
fs
函数或使用承诺。异步回调不是一种好的样式


此外,您还询问了剥离扩展的问题。你应该一个接一个地提问。没有人会为你写一个完整的解决方案

要使代码在不同的环境中平稳运行,path.resolve可用于操作path的位置。下面是工作得更好的代码

阅读部分:

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 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('dirname/', function(filename, content) {
  data[filename] = content;
}, function(err) {
  throw err;
});
var data = {};
readFiles(path.resolve(__dirname, 'dirname/'), function(filename, content) {
  data[filename] = content;
}, function(error) {
  throw err;
});

这是前一个版本的现代版
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 );
});
假设您有另一个文件夹列表,您也可以遍历该列表,因为内部promise.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
起到了神奇的作用。它接受签名
函数(项、索引、解析、拒绝)
的功能块,其中
是数组中的当前项,
索引
它在数组中的位置,
解析
拒绝
回调函数。 每个承诺将在当前
索引
处的数组中推送,并通过匿名函数调用将当前
作为参数:

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

另一个版本使用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));

你是像我一样懒惰的人吗?喜欢npm模块。那么看看这个

npm安装

读取文件的示例:

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

如果您有Node.js 8或更高版本,则可以使用新的util.promisify。(我将代码中与重新格式化为对象有关的部分标记为可选,这是原始帖子要求的。)


对于以下所有示例,您需要导入和安装模块:

const fs=require('fs');
const path=require('path');
异步读取文件
函数读取文件(dir,processFile){
//读取目录
fs.readdir(dir,(错误,文件名)=>{
如果(错误)抛出错误;
fileNames.forEach(文件名=>{
//获取当前文件名
const name=path.parse(filename).name;
//获取当前文件扩展名
const ext=path.parse(filename).ext;
//获取当前文件路径
const filepath=path.resolve(dir,filename);
//获取有关该文件的信息
fs.stat(文件路径,函数(错误,stat){
如果(错误)抛出错误;
//检查当前路径是文件还是文件夹
const isFile=stat.isFile();
//排除文件夹
if(isFile){
//回调,对文件做些什么
processFile(文件路径、名称、ext、stat);
}
});
});
});
}
用法:

//使用文件所在文件夹的绝对路径
readFiles('absolute/path/to/directory/',(filepath、name、ext、stat)=>{
log('file path:',filepath);
log('文件名:',名称);
log('文件扩展名:',ext);
log('文件信息:',stat);
});
同步读取文件、存储在阵列中、自然排序
/**
*@description通过自然排序从文件夹同步读取文件
*@param{String}dir目录的绝对路径
*@返回{Object[]}对象列表,每个对象代表一个文件
*结构如下:`{filepath,name,ext,stat}`
*/
函数readFilesSync(dir){
常量文件=[];
fs.readdirSync(dir.forEach)(文件名=>{
const name=path.parse(filename).name;
const ext=path.parse(filename).ext;
const filepath=path.resolve(dir,filename);
const stat=fs.statSync(文件路径);
const isFile=stat.isFile();
if(isFile)files.push({filepath,name,ext,stat});
});
文件排序((a,b)=>{
//自然排序字母数字字符串
// https://stackoverflow.com/a/38641281
返回a.name.localeCompare(b.name,未定义,{numeric:true,敏感度:'base'});
});
归还文件;
}
用法:

//返回对象的数组列表
//每个对象代表一个文件
const files=readFilesSync('absolute/path/to/directory/');
使用promise异步读取文件 更多信息请点击这里

const{promisify}=require('util');
const readdir_promise=promisify(fs.readdir);
const stat_promise=promisify(fs.stat);
函数readfileasync(dir){
返回readdir_promise(dir,{encoding:'utf8'})
。然后(文件名=>{
const files=getFiles(dir,文件名);
返回承诺。所有(文件);
})
.catch(err=>console.error(err));
}
函数getFiles(dir,filename){
返回filenames.map(文件名=>{
const name=path.parse(filename).name;
const ext=path.parse(filename).ext;
const filepath=path.resolve(dir,filename);
返回stat({name,ext,filepath});