【问题标题】:How to list all subdirectories and files using nodeJS?如何使用 nodeJS 列出所有子目录和文件?
【发布时间】:2020-02-12 23:24:21
【问题描述】:


使用节点 ssh2-sftp-client,我想递归地列出 SSH 远程目录根目录的所有目录(以及第二次,文件)。

我正在使用nodejs

node v12.15.0

我发现了一个有用的same but non answered StackOverflow question

文档“基本用法”(参见 ssh2-sftp-client)给出了 sftp 连接的标准用法和目录 '/tmp' 的列表:

const Client = require('ssh2-sftp-client');
const sshConfig = {
    host: process.env.REMOTE_SSH_HOST,
    port: 22,
    username: process.env.REMOTE_SSH_USERNAME,
    password: process.env.REMOTE_SSH_PASSWORD,
    readyTimeout: 99999,
};
let sftp = new Client();
sftp.connect(sshConfig).then(() => {
    return sftp.list('/tmp');
}).then(data => {
    console.log(data, 'the data info');
}).catch(err => {
    console.log(err, 'catch error');
});

我尝试添加一个函数以递归方式读取每个子目录,但我在 forEach 语句中出现错误:

sftp.list(...).forEach is not a function

虽然 sftp.list() 返回一个数组。
我知道 sftp.list 方法有一些东西会返回一个 Promise,然后是一个数组,但无法弄清楚我应该修改什么以及在哪里修改。

这是我的代码:
sshList.js

const Client = require('ssh2-sftp-client');
const sshConfig = {
    host: process.env.REMOTE_SSH_HOST,
    port: 22,
    username: process.env.REMOTE_SSH_USERNAME,
    password: process.env.REMOTE_SSH_PASSWORD,
    readyTimeout: 99999,
};
let sftp = new Client();

// Function to read sub-directories
async function SubRead(sub, parentDirectory) {
    if (sub['type'] === 'd') {
        await Read(parentDirectory + '/' + sub['name']);
    }
}
async function Read(directory) {
    console.log('Read(' + directory + ')');
    const result = sftp.list(directory);
    result.forEach( x => SubRead(x, directory) );
}
async function main(directory) {
    try {
        console.log('Connecting...');
        await sftp.connect(sshConfig).then(async () => {
            console.log('Connected');
            await Read(directory);
        });
    } catch (e) {
        console.error(e.message);
    } finally {
        console.log('Closing session...');
        await sftp.end();
        console.log('Session closed.');
    }
}
console.log('Application started');
main('/home/user/path').then(r => {
    console.log('Application ended.');
});

启动

node sshList.js

添加示例结构

假设要读取的远程目录“/home/user/path”具有这种树结构:

.
├── Level1_A
│   ├── Level2_AA
│   │   ├── Level3_AAA
│   │   ├── toto
│   │   ├── toto.txt
│   │   ├── txttoto
│   │   └── txt.toto
│   ├── Level2_AB
│   └── Level2_AC
├── Level1_B
│   ├── Level2_BA
│   ├── Level2_BB
│   └── Level2_BC
└── Level1_C
    ├── Level2_CA
    └── Level2_CB

运行节点命令(见上)给出不完整的结果:

Application started
Connecting...
Connected
Reading(/home/iliad/alain)
Reading(/home/iliad/alain/Level1_B)
Reading(/home/iliad/alain/Level1_A)
Reading(/home/iliad/alain/Level1_C)
Closing session...
Session closed.
Application ended.

找不到“2 级”目录!
我期待(不要考虑“# Missing”文本):

Application started
Connecting...
Connected
Reading(/home/iliad/alain)
Reading(/home/iliad/alain/Level1_B)
Reading(/home/iliad/alain/Level1_B/Level2_BA) # Missing
Reading(/home/iliad/alain/Level1_B/Level2_BB) # Missing
Reading(/home/iliad/alain/Level1_B/Level2_BC) # Missing
Reading(/home/iliad/alain/Level1_A)
Reading(/home/iliad/alain/Level1_A/Level2_AA) # Missing
Reading(/home/iliad/alain/Level1_A/Level2_AA/Level4_AAA) # Missing
Reading(/home/iliad/alain/Level1_A/Level2_AB) # Missing
Reading(/home/iliad/alain/Level1_A/Level2_AC) # Missing
Reading(/home/iliad/alain/Level1_C)
Reading(/home/iliad/alain/Level1_C/Level2_CA)
Reading(/home/iliad/alain/Level1_C/Level2_CB)
Closing session...
Session closed.
Application ended.

我错过了什么?
欢迎任何帮助!

【问题讨论】:

  • 试试 await SubRead 吗?不知道
  • @RenaudReguieg 我目前正在朝这个方向进行测试,但没有任何改进:(

标签: javascript node.js ssh


【解决方案1】:

sftp.list 返回一个承诺,所以你需要在使用它之前等待它。像这样的东西应该可以工作

const Client = require('ssh2-sftp-client');
const sshConfig = {
    host: process.env.REMOTE_SSH_HOST,
    port: 22,
    username: process.env.REMOTE_SSH_USERNAME,
    password: process.env.REMOTE_SSH_PASSWORD,
    readyTimeout: 99999,
};
let sftp = new Client();

async function Read(directory) {
    console.log('Read(' + directory + ')');
    const result = await sftp.list(directory);
    for(const sub of result) {
      if (sub['type'] === 'd') {
          await Read(directory + '/ ' + sub['name']);
      }
    }
}

async function main(directory) {
    try {
        console.log('Connecting...');
        await sftp.connect(sshConfig).then(() => {
            console.log('Connected');
            await Read(directory);
        });
    } catch (e) {
        console.error(e.message);
    } finally {
        console.log('Closing session...');
        await sftp.end();
        console.log('Session closed.');
    }
}
console.log('Application started');
main('/home/user/path').then(r => {
    console.log('Application ended.');
});

【讨论】:

  • 感谢@Ashish-Modi 不幸的是,这仅在一个子级别中运行,而不是全部。
  • 我已经修改了关于您的 cmets 的来源,并添加了一个示例来增强我的问题。
  • @AlainL。我已经修改了用于 for..of 的代码,因为 foreach 并不真正重视承诺。希望这行得通。
  • 有效!关于承诺的好点! - 只是为了记录,我更正了句子“directory + '/' + sub['name']”,因为“/”后面有多余的空格。非常感谢!
  • 要解决数组中的承诺,你应该看看 Promise.all()
【解决方案2】:

sftp.list(目录).forEach(

必须是:

 sftp.list(directory).then((myList)=> {myList.foreach()})//with your code
                     .catch((err)=> console.log(err))//never forget to catch

或者声明你的函数是异步的并且

try{
const myList = await sftp.list(directory);
}catch(err){console.log(err)}//NEVER forget to catch

【讨论】:

    猜你喜欢
    • 2014-09-12
    • 1970-01-01
    • 2016-01-16
    • 2011-12-24
    • 2019-07-06
    • 2018-07-13
    • 2012-11-14
    • 2014-10-16
    相关资源
    最近更新 更多