2016-05-22 47 views
5

Node.jsの読み取りストリームで作業するのはかなり奇妙な問題があります。私はSSH2を使用して私とSFTPサーバー間のSFTP接続を作成しています。次に、sftpストリームから読み込みストリームを作成しようとします。読み込まれたストリームの放出された 'data'イベントから、データを配列に追加します。読み込みストリームの 'close'イベントが発生すると、私はBuffer.concatを呼び出して、1つのバッファに取り込んだすべてのデータの連結を作成します。これは、ここでスタックオーバーフローで尋ねられる他の質問に記載されているのと同じテクニックです。たとえば、hereとなります。しかし、私は取得したデータを使用することができません。それはバッファのサイズが私は(取得されたデータの長さを数える)から取得しようとしているファイルのサイズが32バイト少ないようです。これは私のSFTP接続と関係がありますか?または、私の読み込みストリームをどのように作成するのですか?Node.jsとSSH2を使用してSFTPサーバーからファイルを読み取る

重要な場合、ファイルのタイプはzipです。バッファに読み込んだ後にファイルを(node.jsと手動で)解凍しようとすると、うまくいきません。私は、ファイル上のreaddirを使用すると、ファイルのサイズが正しい

  1. 調査した後、私はあることを見出しました。

  2. 私の開発用FTPサーバー(JSFTP)を使用すると、上記の同じ手法を使用してうまく動作します。

アドバイスはありがとうございます。ここで

は私のコードです:

 var Client = require('ssh2').Client; 
     var m_ssh2Credentials = { 
      host: config.ftpHostName, 
      port: config.ftpPort, 
      username: config.ftpUser, 
      password: config.ftpPassword, 
      readyTimeout: 20000, 
      algorithms: { cipher: ["3des-cbc", "aes256-cbc", "aes192-cbc","aes128-cbc"]} 
     }; 
     ... 
     var conn = new Client(); 
     var dataLength = 0; 
     conn.on('ready', function() { 
      conn.sftp(function(err, sftp) { 
       if (err) { 
        writeToErrorLog("downloadFile(): Failed to open SFTP connection."); 
       } else { 
        writeToLog("downloadFile(): Opened SFTP connection."); 
       } 

       var streamErr = ""; 
       var dataLength = 0; 
       var stream = sftp.createReadStream(config.ftpPath + "/" + m_fileName) 
       stream.on('data', function(d){ 
        data.push(d); 
        dataLength += d.length; 
       }); 
       .on('error', function(e){ 
        streamErr = e; 
       }) 
       .on('close', function(){ 
        if(streamErr) { 
         writeToErrorLog("downloadFile(): Error retrieving the file: " + streamErr); 
        } else { 
         writeToLog("downloadFile(): No error using read stream."); 
         m_fileBuffer = Buffer.concat(data, dataLength); 
         writeToLog("Data length: " + dataLength); 

         writeToLog("downloadFile(): File saved to buffer."); 
        } 
        conn.end(); 
       }); 
      }) 
     }) 
     .on('error', function(err) { 
      writeToErrorLog("downloadFile(): Error connecting: " + err); 
     }).connect(m_ssh2Credentials); 

答えて

7

だから捜査多くの後、私は最終的に「データ」イベントで送信されたデータの最後のビットに何か問題があったことに気づきました。私の理解から、読み込みストリームの実装にはバグがあるようです。 SSH2ライブラリでより単純な関数(open、fstat、read)を使うことで、この問題を回避することができました。このソリューションは私のために働く。他の誰かが同じ問題を抱えている場合、その解決方法を共有したい

の作業コード:

sftp.open(config.ftpPath + "/" + m_fileName, "r", function(err, fd) { 
sftp.fstat(fd, function(err, stats) { 
    var bufferSize = stats.size, 
     chunkSize = 16384, 
     buffer = new Buffer(bufferSize), 
     bytesRead = 0, 
     errorOccured = false; 

    while (bytesRead < bufferSize && !errorOccured) { 
     if ((bytesRead + chunkSize) > bufferSize) { 
      chunkSize = (bufferSize - bytesRead); 
     } 
     sftp.read(fd, buffer, bytesRead, chunkSize, bytesRead, callbackFunc); 
     bytesRead += chunkSize; 
    } 

    var totalBytesRead = 0; 
    function callbackFunc(err, bytesRead, buf, pos) { 
     if(err) { 
      writeToErrorLog("downloadFile(): Error retrieving the file."); 
      errorOccured = true; 
      sftp.close(fd); 
     } 
     totalBytesRead += bytesRead; 
     data.push(buf); 
     if(totalBytesRead === bufferSize) { 
      m_fileBuffer = Buffer.concat(data); 
      writeToLog("downloadFile(): File saved to buffer."); 
      sftp.close(fd); 
      m_eventEmitter.emit('downloadFile_Complete'); 
     } 
    } 
}); 
0

バイトサイズ(またはチャンクサイズ)が必須ではありませんし、あなただけのファイルを取得する必要がある場合は、はるかに優れた軽量-と、より高速な方法は、ええ(そこにあると思います。 .. nodejs方法!)。 、あなたはまた、パラレルを使用していますすぐにファイルを持って読みsftp.fastGet()を試すことができます別の方法として

function getFile(remoteFile, localFile) { 
    conn.on('ready', function() { 
    conn.sftp(function (err, sftp) { 
     if (err) throw err; 
     var rstream = sftp.createReadStream(remoteFile); 
     var wstream = fs.createWriteStream(localFile); 
     rstream.pipe(wstream); 
     rstream.on('error', function (err) { // To handle remote file issues 
      console.log(err.message); 
      conn.end(); 
      rstream.destroy(); 
      wstream.destroy(); 
     }); 
     rstream.on('end', function() { 
      conn.end(); 
     }); 
     wstream.on('finish', function() { 
      console.log(`${remoteFile} has successfully download to ${localFile}!`); 
     }); 
    }); 
    }).connect(m_ssh2Credentials); 
} 

:これは私がファイルをコピーするために使用する方法です。 fastGet()は、パラレル読み取りとチャンクサイズの数を設定する方法とは別に、ダウンロードの進行状況を表示する方法(必要な場合)を提供します。詳細を知るには、SFTPStream docを開き、fastGetを検索してください。

sftp.fastGet(remoteFile, localFile, function (err) { 
    if (err) throw err; 
    console.log(`${remoteFile} has successfully download to ${localFile}!`); 
} 

HIH:

はここで非常に速いコードです!

+0

sftp.fastGet/fastDownloadの問題は、一時停止機能を提供していないが、ストリームができることです。 –

関連する問題