2012-04-06 96 views
37

我不知道這是否可行,但在這裏。並且使用回調工作會更加困難。讀取目錄中的所有文件,將它們存儲在對象中,然後發送對象

我有一個帶有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}); 

最後的回調也是錯誤的。當目錄中的所有文件都完成時,它必須被調用。

但我不知道如何創建代碼,任何人都知道這是否有可能?

+3

如果同步訪問正常,則可以使用(阻塞)'readfileSync'和'readdirSync'方法。 http://nodejs.org/docs/v0.4.8/api/fs.html#fs.readdirSync – rjz 2012-04-06 21:42:29

+0

好吧,我不知道readdir,這可以是有幫助的。阻塞的缺點是什麼?我認爲node.js的重點是它是非阻塞的?爲什麼我們可以突然阻止。 – 2012-04-06 21:51:42

+0

對於異步回調閱讀此:http://stackoverflow.com/questions/18983138/callback-after-all-asynchronous-foreach-callbacks-are-completed 有很多錯誤的答案,但有些是正確的。其中一個使用計數器。 – Vanuan 2015-12-23 18:07:21

回答

88

所以,有三個部分。閱讀,存儲和發送。

這裏的閱讀部分:

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。異步回調不是一個好的風格。

此外,你問關於剝離擴展。你應該逐個進行問題。沒有人會爲你寫一個完整的解決方案。

+0

謝謝,我想我會用這個。有一件事,你能解釋一下'0 === - c'的功能嗎。 – 2012-04-06 22:09:14

+0

你可以把它寫成兩行'c - ',然後'if(c === 0)'就是這樣。它只是通過'1'遞減'c'並檢查它是否爲零 – stewe 2012-04-06 22:13:01

+0

但它總是0,或者不是?你在foreach中加1,在同樣的foreach中刪除1,所以它總是保持爲0,或者我錯了嗎?不需要檢查'if(c === files.length)',就像那樣。 – 2012-04-06 22:19:36

1

要使代碼在不同環境下順暢工作,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; 
}); 
+0

正如你所說,你還沒有[贏得](// meta.stackoverflow.com/q/146472/169503)足夠的[聲譽](// stackoverflow.com/help/whats-reputation)[評論任何帖子](// stackoverflow.com/help/privileges/comment)。但是,請[不要濫用*發佈答案*按鈕](// meta.stackoverflow.com/a/277942/2747593)因此。相反,[在網站上花費一些時間並提出問題或提供答案](// meta.stackexchange.com/a/188621/269535),這會爲您提供所需的代表。 – 2016-08-24 22:14:15

+0

@ScottWeldon接受的答案有問題。我不確定你的觀點是否有效。我會保留這個答案,它可能會幫助他人。不要誤解我的意思,但我不需要聲望或觀點。 :) – rsa 2016-08-24 23:42:37

10

這是一個現代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); 
      }); 
     }); 
    }); 
} 

How使用方法:

一樣簡單做:

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確實神奇

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

:所有將解決每個然後異步。它採用簽名爲function(item,index,resolve,reject)的功能塊,其中item是陣列中的當前項目,index在陣列中的位置,resolverejectPromise回調函數。

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

另一個版本 每個承諾將在陣列中的當前index並與當前item通過一個匿名函數調用的參數推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)); 
0

你懶惰的人喜歡我,愛NPM模塊:d,然後檢查了這一點。

NPM安裝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 
    });  
0

如果你有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); 
    }); 
相關問題