2012-04-06 9 views
37

これが可能かどうかわかりませんが、ここには入ります。コールバックを使用すると、さらに難しくなります。ディレクトリ内のすべてのファイルを読み込み、オブジェクトに格納してオブジェクトを送信します。

私はnode.jsとsocket.ioのオブジェクトチャンクでクライアントに返信したいhtmlファイルのディレクトリを持っています。

すべての私のファイルは、/ 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

+0

わかりました。私はreaddirについてよく分かりませんでした。ブロッキングの弱点は何ですか?私はnode.jsの全体的なポイントは、それがnon-blockingだったと思ったのですか?なぜ私たちはすべて突然ブロックすることができます。 –

+0

非同期コールバックの場合、これを読んでください:http://stackoverflow.com/questions/18983138/callback-after-all-asynchronous-foreach-callbacks-are-completed 多くの間違った答えがありますが、いくつかは正しいです。それらの1つはカウンタを使用します。 – Vanuan

答えて

88

したがって、3つの部分があります。読書、保管、送付。ここで

は、読取部です:

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

送信部は、あなた次第です。あなたは1つずつまたは完了した後に送ることができます。

完了後にファイルを送信する場合は、fs機能の同期バージョンを使用するか、約束を使用する必要があります。非同期コールバックは良いスタイルではありません。

また、拡張機能の削除について尋ねました。あなたは質問を一つずつ進めるべきです。誰もあなたのために完全な解決策を書くことはありません。

+0

ありがとう、私はこれを使用すると思います。 1つのことtho、 '0 === - c'は何を説明することができます。 –

+0

'c - 'と 'if(c === 0)'の2行で書くことができます。 'c'を' 1 'だけ減らしてゼロに達したかどうかを確認します。 – stewe

+0

しかし、それは常に0になるでしょうか?あなたはforeachに1を加え、同じforeachでは1を削除するので、それは常に0のままですか、間違っていますか?チェックは 'if(c === files.length)'のようにする必要はありません。 –

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)、これにより必要な担当者が得られます。 –

+0

@ScottWeldonの回答に問題があります。あなたの視点が有効かどうかはわかりません。私はこの答えを守り、他人を助けるかもしれない。私を間違ってはいけないが、評判やポイントは必要ない。 :) – rsa

10

これは、すべてのファイルが読み込まれたときにすべての約束を解決するためにPromise.allアプローチを使用して、以前のものの現代Promiseバージョンです。

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

を想定し。全ては非同期に、その後の各を解決します:それは

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

を。ファンクションブロックsignを取ります。itemは配列内の現在の項目、indexは配列内の位置、resolveおよびrejectPromiseコールバック関数です。その後、すべての約束が解決される

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持つ配列にプッシュされますプロミスの現代的な方法。

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

例をインストールする:あなたはNode.jsの8以降を持っている場合は、あなたが新しいutil.promisifyを使用することができます

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

。同期アクセスがOKであれば(私はオリジナルのポストは、要求されたオブジェクトとして再フォーマットしなければならないコードのオプションパーツとしてマーキングしています。)

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); 
    }); 
関連する問題