2013-02-17 144 views
2

在試圖學習node.js/socket.io時我一直在創建一個簡單的文件上傳器,它從客戶端瀏覽器獲取數據塊並在服務器端重新組裝。異步文件追加

用於接收塊的socket.io事件如下所示:

socket.on('sendChunk', function (data) { 
    fs.appendFile(path + fileName, data.data, function (err) { 
     if (err) 
     throw err; 
     console.log(data.sequence + ' - The data was appended to file ' + fileName); 
    }); 
    }); 

的問題是數據塊不一定在他們由於異步調用接收的順序追加。典型控制檯輸出看起來是這樣的:

  • 1 - 數據被附加到文件TESTFILE.TXT
  • 3 - 中的數據是附加到文件TESTFILE.TXT
  • 4 - 數據被追加到文件TESTFILE.TXT
  • 2 - 將數據附加到文件TESTFILE.TXT

我的問題是,什麼是實現無阻塞方式這個功能,但執行順序的正確方法。我已經看過像async這樣的圖書館,但真的希望能夠處理它們,而不是創建一個系列,並在所有文件塊都運行後運行。我仍然試圖圍繞所有這些事件驅動流,所以任何指針都很棒。

回答

3

通常你會使用一個等待寫入的數據的隊列,然後每當前一個append完成時,就嘗試寫下一個片段。事情是這樣的:

var parts = []; 
var inProgress = false; 
function appendPart(data){ 
    parts.push(data); 
    writeNextPart(); 
} 

function writeNextPart(){ 
    if (inProgress || parts.length === 0) return; 

    var data = parts.shift(); 
    inProgress = true; 
    fs.appendFile(path + fileName, data.data, function (err) { 
    inProgress = false; 
    if (err) throw err; 
    console.log(data.sequence + ' - The data was appended to file ' + fileName); 

    writeNextPart(); 
    }); 
} 

socket.on('sendChunk', function (data) { 
    appendPart(data); 
}); 

您將需要擴大這一保留基於文件的partsinProgress隊列。我的例子假設這些將簡單的恆定。

+0

我喜歡它。任何你知道的npm實現?似乎它可能是一個共同的需要有一個監視隊列映射給定的功能... – Vince 2013-02-17 05:52:29

+0

我也喜歡它。但是在writeNextPart()中,不應該使用「parts.shift()」,而應該有一些邏輯來跟蹤最近寫入的序列號,並查看下一個需要的序列號是否可用於「parts」 ?也就是說,如果我們還沒有向文件寫入任何內容並且seq#2到達,我們應該繼續排隊部分,直到seq#1到達,此時我們會處理它? – 2013-02-17 17:55:31

+0

@DanielChisholm好點,我不知道。我假定這些部分都來自同一個客戶端,並且SocketIO將保留'sendChunk'事件的順序。如果它不保留訂單,那麼這將是必要的。 – loganfsmyth 2013-02-17 18:46:22

0

由於您需要附加順序或同步。您可以使用fs.appendFileSync而不是fs.appendFile。這是處理它的最快方式,但它會損害性能。

如果您想自己異步處理它,請使用EventEmitter處理此問題的流。事實證明,響應(以及請求)對象是流。用fs.createWriteStream創建一個可寫入的流並寫入所有片段以追加文件。

fs.createWriteStream(path, [options])# 
Returns a new WriteStream object (See Writable Stream). 

options is an object with the following defaults: 

{ flags: 'w', 
    encoding: null, 
    mode: 0666 } 

你的情況,你可以使用標誌: 'A'

+0

我實際上嘗試appendFileSync最初只是爲了它,因爲某些原因隨機塊的文件丟失。我正在運行這個本地和使用小塊大小,所以不知道許多同時調用追加在同一個文件莫名其妙或相互毆打。有了writestream,我仍然需要擔心排序和排隊的問題嗎? – Vince 2013-02-17 20:42:47