You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用NodeJS实现SFTP到SMB的流式文件传输(仅传3天内新文件)

问题描述

我尝试使用NodeJS脚本将SFTP服务器中的文件复制到SMB共享目录,但仅复制创建时间不超过3天的新文件。目前已完成代码基础框架,但不清楚如何将SFTP上的文件以流的形式读取,再流式写入SMB共享,以此避免因文件过大而使用本地存储进行下载再上传的循环。相关代码如下:

const path = require('path');
const sftp = require('ssh2-sftp-client');
const smb2 = require('smb2');
const config = require('./config');

function extractTimestamp(filename) {...} // works fine
function calculateAgeFromTimestamp(timestamp) {...} // also works fine

async function processFiles() {
  const sftpClient = new sftp();
  const smbClient = new smb2(config.smb);

  try {
    await sftp.connect(config.sftp);
    console.log(`Listing remote SFTP source: ${config.sourceDir}`);
    const files = await sftp.list(config.sourceDir);

    if (files.length === 0) {
      console.log('No files found on SFTP.');
      return;
    }

    for (const file of files) {
      const sourceFilePath = path.join(config.sourceDir, file.name);
      const destinationFilePath = config.smb.share + '\\' + file.name;

      const timestamp = extractTimestamp(file.name);
      const fileAgeDays = calculateAgeFromTimestamp(timestamp);

      if (fileAgeDays <= 3) {
        const exists = await new Promise((resolve, reject) => {
          smbClient.exists(destinationFilePath, (err, exists) => {
            if (err) {
              console.error('Error checking file existence on SMB:', err);
              reject(err);
            } else {
              resolve(exists);
            }
          });
        });

        if (!exists) {
          console.log('Found file to copy');

          // !!!confusing stream code goes here
         
        } else {
          console.log('File already exists');
        }
      }
    }
  } catch (error) {
    console.error('Error:', error);
  } finally {
    sftp.end();
    smbClient.close();
  }
}

processFiles();

请问是否可以通过某种包装器将SFTP的文件读取转换为流?

解决方案

完全可以实现流式传输,不需要本地存储中转。你可以利用ssh2-sftp-client提供的createReadStream方法读取SFTP文件流,再通过smb2的createWriteStream方法写入SMB共享,最后将两个流通过pipe连接起来即可。

把以下代码替换掉你标注的// !!!confusing stream code goes here部分:

// 用Promise包装流操作,确保异步流程等待复制完成
await new Promise((resolve, reject) => {
  // 创建SFTP读取流
  const readStream = sftpClient.createReadStream(sourceFilePath);
  // 创建SMB写入流
  const writeStream = smbClient.createWriteStream(destinationFilePath);

  // 处理流的错误
  readStream.on('error', (err) => {
    console.error(`Failed to read SFTP file ${sourceFilePath}:`, err);
    reject(err);
  });

  writeStream.on('error', (err) => {
    console.error(`Failed to write SMB file ${destinationFilePath}:`, err);
    reject(err);
  });

  // 复制完成时触发
  writeStream.on('finish', () => {
    console.log(`Successfully copied ${file.name} to SMB share`);
    resolve();
  });

  // 连接两个流,开始传输
  readStream.pipe(writeStream);
});

注意事项

  • 确保ssh2-sftp-client和smb2的版本支持流操作(当前主流版本都支持)。
  • 流操作是异步的,必须用Promise包装并await,否则循环会在文件复制完成前继续执行下一个文件,可能导致资源冲突。
  • 错误处理要覆盖读写两个流的异常,避免单个文件复制失败导致整个脚本崩溃。

内容的提问来源于stack exchange,提问作者Dycey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 21:12:49