2016-05-22 21 views
5

Tôi gặp sự cố khá lạ khi làm việc với luồng đọc trong Node.js. Tôi đang sử dụng SSH2 để tạo ra một kết nối sftp giữa tôi và một máy chủ sftp. Sau đó tôi cố gắng tạo luồng đọc từ luồng sftp. Từ sự kiện 'dữ liệu' được phát ra của luồng đọc, tôi nối dữ liệu vào một mảng. Khi sự kiện 'close' của dòng đọc xảy ra, tôi thực hiện cuộc gọi đến Buffer.concat để tạo ra concat tất cả các khối dữ liệu mà tôi đã truy xuất vào một bộ đệm. Đây là kỹ thuật tương tự được mô tả trong các câu hỏi khác được hỏi ở đây tại tràn ngăn xếp. Ví dụ: here. Tuy nhiên, tôi không thể sử dụng dữ liệu tôi truy xuất. Dường như bộ đệm có kích thước nhỏ hơn 32 byte thì tệp tôi đang cố gắng truy xuất (tính thời lượng dữ liệu được truy lục). Điều này có liên quan gì đến kết nối SFTP của tôi không? Hoặc cách tôi tạo luồng đọc của mình?Đọc tệp từ máy chủ SFTP bằng Node.js và SSH2

Nếu có vấn đề, tệp thuộc loại zip. Khi tôi cố gắng giải nén tập tin (trong node.js và thủ công) sau khi đọc nó để đệm nó không hoạt động.

Sau khi điều tra tôi đã phát hiện ra rằng:

  1. Khi tôi sử dụng readdir vào file, kích thước của tập tin là đúng.
  2. Sử dụng FTP (JSFTP) để phát triển máy chủ FTP của tôi hoạt động tốt bằng cách sử dụng kỹ thuật tương tự ở trên.

Bất kỳ lời khuyên nào được đánh giá cao!

Đây là mã của tôi:

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

Trả lời

7

Vì vậy, sau rất nhiều cuộc điều tra cuối cùng tôi nhận ra rằng có điều gì đó sai trái với các bit cuối cùng của dữ liệu đã được truyền trong trường hợp 'dữ liệu'. Từ sự hiểu biết của tôi nó có vẻ là một lỗi trong việc thực hiện các dòng đọc. Tôi đã có thể nhận được xung quanh vấn đề này bằng cách sử dụng các chức năng đơn giản hơn (mở, fstat, đọc) trong thư viện SSH2. Giải pháp này làm việc cho tôi. Muốn chia sẻ giải pháp nếu ai đó gặp phải vấn đề tương tự.

đang làm việc:

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

Nếu kích thước byte (hoặc kích thước đoạn) là không bắt buộc và bạn chỉ cần để có được các tập tin, đoán có một tốt hơn-và-nhanh nhẹ hơn cách (yeah. .. the nodejs way!). Đây là cách tôi sử dụng để sao chép tệp:

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

Thay vào đó, bạn cũng có thể thử đọc song song để mang tệp nhanh chóng. fastGet() cung cấp cho bạn một cách để hiển thị tiến trình tải xuống (nếu muốn) ngoài việc đưa ra một cách để định cấu hình số lần đọc song song và kích thước chunk. Để biết thêm, hãy mở số SFTPStream doc này và tìm kiếm fastGet.

Dưới đây là một mã rất nhanh:

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

HIH!

+0

vấn đề của sftp.fastGet/fastTải xuống là nó không cung cấp chức năng tạm dừng, nhưng luồng có thể. –

Các vấn đề liên quan