Nodejs - 将所有文件从 ftp 下载到本地文件夹并移动到另一个 ftp 文件夹的脚本

Nodejs - script that download all file from ftp to local folder and move on to another ftp folder

我正在尝试下载 FTP 站点上特定文件夹中的所有文件。该文件夹名为“IN”(如示例代码所示)并包含许多 .csv 文件。

要求是这样的:

  1. 将 IN 文件夹中存在的所有 csv 下载到本地文件夹
  2. 将它们从 FTP 上的 IN 文件夹移动到 ftp 文件夹上的 ARCHIVE 文件夹
  3. 将所有 csv 文件合并到新的 csv 中,并导入 csv 的所有内容

我卡在第二点了。我使用 promise-ftp 来完成这个过程,这里是我的代码:

const fs = require("fs");
const Client = require("promise-ftp");
const sftp = new Client();

sftp
  .connect({
    host: "xxxxx",
    port: 21,
    user: "xxxx",
    password: "xxxxx",
  })
  .then(() => {
    console.log("connected");
    // will return an array of objects with information about all files in the remote folder
    return sftp.list("/htdocs/IN");
  })
  .then(async (data) => {
    // data is the array of objects
    len = data.length;
    // x is one element of the array
    await data.forEach((x) => {
      let remoteFilePath = "/htdocs/IN/" + x.name;
      if (x.type === "-") {
        console.log(x.name);
        sftp
          .get(remoteFilePath)
          .then((stream) => {
            console.log("---------");
            console.log(x.name);
            return new Promise(function (resolve, reject) {
              stream.once("close", resolve);
              stream.once("error", reject);
              stream.pipe(fs.createWriteStream("IN/" + x.name));
            });
          })
          .then(() =>{
            sftp
              .rename("/htdocs/IN/" + x.name, "/htdocs/OUT/" + x.name)
              .then(function () {
                console.log("rinominato");
              })
            console.log("qui cancello: " + x.name);
          });
      }
    });
  }).then(() => {
    sftp.end();
  })
  .catch((err) => {
    console.log(err, "catch error");
  });

现在这个脚本下载了我本地存储中的所有文件,但是当我试图将它重命名为另一个文件夹时,我收到这个错误:

Unhandled rejection FtpConnectionError: can't perform 'rename' command when connection status is: disconnecting

我认为我在放置 sftp.close 函数的位置上犯了一些错误,但我是 node.js 的新手。

任何人都可以帮助我更好地理解我错在哪里?

添加了新版本 的代码,其中包含更多异步和等待,但仍然无法正常工作:

const fs = require("fs");
const Client = require("promise-ftp");
const ftp = new Client();

const downloadAndStoreFile = async () => {
    await ftp.connect({
      host: "xxxx",
      port: 21,
      user: "xxx",
      password: "xxx",
    });

    console.log ('connected');

    let data = await ftp.list('/htdocs/IN');
    data = data.filter(function (file) {
      return file.type === "-" ? file : null;
    });
    console.log(data);

    data.forEach((file)=>{
        if (file.type === '-'){
          //console.log(file.name);
          const operation = async () => {
            console.log(file.name);
            const stream = await ftp.get("/htdocs/IN/" + file.name);
            const streamResult = await stream.pipe(fs.createWriteStream("IN/" + file.name));
            const renameResult = await ftp.rename("/htdocs/IN/" + file.name, "/htdocs/OUT/" + file.name);
          };
          operation();
        }
    });

    await ftp.end();
};

downloadAndStoreFile();

谢谢

请尝试使用 await 方式来做这样的事情:

const fs = require("fs");
const Client = require("promise-ftp");
const sftp = new Client();

sftp
    .connect({
        host: "XXXX",
        port: 21,
        user: "XXX",
        password: "XXX",
    })
    .then(() => {
        console.log("connected");
        // will return an array of objects with information about all files in the remote folder
        return sftp.list("/htdocs/IN");
    })
    .then(async(data) => {
        // data is the array of objects
        len = data.length;

        for (let i = 0; i < len; i++) {
            let x = data[i]; // x is one element of the array

            let remoteFilePath = "/htdocs/IN/" + x.name;
            if (x.type === "-") {
                console.log(x.name);
                let stream = sftp.get(remoteFilePath);

                console.log("---------");
                console.log(x.name);

                await stream.pipe(fs.createWriteStream("IN/" + x.name));

                await sftp.rename("/htdocs/IN/" + x.name, "/htdocs/OUT/" + x.name)
                console.log("rinominato");
                console.log("qui cancello: " + x.name);
            }
        }
    }).then(() => {
        sftp.end();
    })
    .catch((err) => {
        console.log(err, "catch error");
    });

您遇到的错误非常具有描述性:

Unhandled rejection FtpConnectionError: can't perform 'rename' command when connection status is: disconnecting

我们可以从中得出结论,当客户端尝试断开连接时,正在调用 rename。问题在于在 forEach 循环中进行异步调用,因为您在结束连接之前没有等待它们解决。

一种可能的解决方案是将操作映射到 promise 数组并调用 Promise.all

    Promise.all(
      data
       .filter((file) => file.type === "-")
       .map((file) => {
          const operation = async () => {
          const stream = await ftp.get("/htdocs/IN/" + file.name);
          const streamResult = await stream.pipe(
            fs.createWriteStream("IN/" + file.name)
          );
          const renameResult = await ftp.rename(
            "/htdocs/IN/" + file.name,
            "/htdocs/OUT/" + file.name
          );
      };
      return operation();
    })
);