使用nodejs连接ftp上传下载

使用nodejs连接ftp上传下载

月光魔力鸭

2019-01-16 10:20 阅读 4357 喜欢 9 ftp上传 nodejs连接ftp

通过nodejs连接ftp,对ftp进行操作,包括查询列表、下载、上传。

依赖

//ftp 模块是目前找到的还不错的,对于ftp的基本功能都支持
npm install ftp

连接ftp

const ftp = require('ftp');//连接FTP
const client = new ftp();
client.on('ready',()=>{
    console.log('ftp client is ready');
});
client.connect({
    host : '***.***.***.***',
    port : '****',
    user : '***',
    password : '***',
    keepalive : 1000
});

调用后

ftp 获取列表 list

//列出目标目录
function list(dirpath){
    return new Promise((resolve,reject)=>{
        client.list((err,files)=>{
            resolve({err : err,files : files});
        })
    });
}
async function test (){
    //list 列表功能
    let {err,files} = await list();
    if(err){
        console.log(err);
        return
    }
    console.log(`获得文件列表:`+files.length);
    console.log(files);
}
test();

获取结果

ftp 目录切换

//切换目录
function cwd(dirpath){
    return new Promise((resolve,reject)=>{
        client.cwd(dirpath,(err,dir)=>{
            resolve({err : err,dir : dir});
        })
    });
}

FBI WARNING : 这里提醒下,在本示例中的所有代码都在同一个文件中,后面会给出完整示例代码。

有了目录切换,那么在list函数中的dirpath就可以使用啦。如下:

//列出目标目录
//列出目标目录
async function list(dirpath){
    let {err : ea,dir } = await cwd(dirpath);
    return new Promise((resolve,reject)=>{
        client.list((err,files)=>{
            resolve({err : err,files : files})
        })
    });
}

ftp 下载文件

//下载文件
async function get(filePath){
    const dirpath = path.dirname(filePath);
    const fileName = path.basename(filePath);
    let {err : ea,dir} = await cwd(dirpath);
    return new Promise((resolve,reject)=>{
        client.get(fileName,(err,rs)=>{
            let ws = fs.createWriteStream(fileName);
            rs.pipe(ws);
            resolve({err : err});    
        });
    });
}

ftp 上传文件

//将文件上传到ftp目标地址
async function put(currentFile,targetFilePath){
    const dirpath = path.dirname(targetFilePath);
    const fileName = path.basename(targetFilePath);
    const rs = fs.createReadStream(currentFile);
    let {err : ea,dir} = await cwd(dirpath);//此处应对err做处理
    if(ea){
        return Promise.resolve({err : ea});
    }
    return new Promise((resolve,reject)=>{
        client.put(rs,fileName,(err)=>{
            resolve({err : err});
        })
    });
}

ftp 断点下载

fs.stat(localFile,(err,stats)=>{
        var startSize = 0;
        if(err){
            console.log('no file here');
        }else{
            startSize = stats.size;
        }
        console.log(`已经下载:${startSize},从此处开始下载`);
        c.restart(startSize,err=>{
            if(err){
                console.log(err);
                process.exit(0);
            }
            c.get(targetFile,(err,rs)=>{
                console.log('start download');
                console.log(rs);
                rs.on('data',data=>{
                    console.log(`写入${data.length}`);
                    rs.pause();
                    fs.appendFile(localFile,data,()=>{
                        rs.resume();
                    });
                })
                rs.on('close',()=>{
                    console.log('download complete')
                    c.end();
                })
                // rs.pipe(fs.createWriteStream(localFile,{start : startSize}))
            })
        })
    })

断点下载目前有个问题还没解决,如果ftp服务器是filezilla server的话,是不行,会追加文件,也可能是我设置的问题,不过目前还没解决方案,如果各位有的话,麻烦给留个言,谢谢啦。

具体的示例截图这里就不展示了,大家可以拿了demo自己测试下。

完整示例代码

const ftp = require('ftp');//连接FTP
const path = require('path');
const client = new ftp();
const fs = require('fs');

client.on('ready',()=>{
    console.log('ftp client is ready');
});
client.on('close',()=>{
    console.log('ftp client has close')
});
client.on('end',()=>{
    console.log('ftp client has end')
});
client.on('error',(err)=>{
    console.log('ftp client has an error : '+ JSON.stringify(err))
});
client.connect({
    host : '***',//这个就不提供啦
    port : '***',
    user : '***',
    password : '***',
    keepalive : 1000
});
//列出目标目录
async function list(dirpath){
    let {err : ea,dir } = await cwd(dirpath);
    return new Promise((resolve,reject)=>{
        client.list((err,files)=>{
            resolve({err : err,files : files})
        })
    });
}
//切换目录
function cwd(dirpath){
    return new Promise((resolve,reject)=>{
        client.cwd(dirpath,(err,dir)=>{
            resolve({err : err,dir : dir});
        })
    });
}
//下载文件
async function get(filePath){
    const dirpath = path.dirname(filePath);
    const fileName = path.basename(filePath);
    let {err : ea,dir} = await cwd(dirpath);
    return new Promise((resolve,reject)=>{
        client.get(fileName,(err,rs)=>{
            let ws = fs.createWriteStream(fileName);
            rs.pipe(ws);
            resolve({err : err});    
        });
    });
}
//将文件上传到ftp目标地址
async function put(currentFile,targetFilePath){
    const dirpath = path.dirname(targetFilePath);
    const fileName = path.basename(targetFilePath);
    const rs = fs.createReadStream(currentFile);
    let {err : ea,dir} = await cwd(dirpath);//此处应对err做处理
    if(ea){
        return Promise.resolve({err : ea});
    }
    return new Promise((resolve,reject)=>{
        client.put(rs,fileName,(err)=>{
            resolve({err : err});
        })
    });
}
async function test (){
    //list 列表功能
    let {err,files} = await list('/attachment/byycampus/resource');
    if(err){
        console.log(err);
        return
    }
    console.log(`获得文件列表:`+files.length);
    console.log(files);

    //下载文件
    let {err : ea} = await get('/attachment/byycampus/resource/201812/14/201812141035222541381967.jpg');
    if(ea){
        console.log(ea);
        return;
    }
    console.log('文件下载成功')

    //文件上传
    let {err : eb} = await put('201812141035222541381967.jpg','/attachment/a.jpg');
    if(eb){
        console.log(eb);
        return;
    }
    console.log('文件上传成功')
}
test();

额外赠送

关于在上传过程中或下载过程中获得速率的问题,在github上也有提出来的,这里简单说下大体的思路,具体可以查看issue.

//将文件上传到ftp目标地址
async function put(currentFile,targetFilePath){
    const dirpath = path.dirname(targetFilePath);
    const fileName = path.basename(targetFilePath);
    const rs = fs.createReadStream(currentFile);
//速率
rs.on('data',d=>{
//在这里把上传的文件的大小记录下来,然后速率可以每隔一秒检查一次已经上传的大小,然后根据上一次的文件大小来计算。
})
    let {err : ea,dir} = await cwd(dirpath);//此处应对err做处理
    if(ea){
        return Promise.resolve({err : ea});
    }
    return new Promise((resolve,reject)=>{
        client.put(rs,fileName,(err)=>{
            resolve({err : err});
        })
    });
}

issue 传送门

参考资料

转载请注明出处: https://chrunlee.cn/article/nodejs-ftp-put-get.html


感谢支持!

赞赏支持
提交评论
评论信息 (请文明评论)
暂无评论,快来快来写想法...
推荐
在使用puppeteer 跳转窗口的时候,发现waitForNavigator 并不起作用,最后找到通过browser 获得page 并继续操作。
最近家里正在装修,实在是不知道怎么做,之前看好好住APP上有不少设计的图,部分还挺好看。。就去看了下有没有WEB端,结果还真有,就有了下文,我抓了几万张图片,然后根据关键字进行分类,从里面找心仪的设计。
做了一个阿里云开发者社区自动签到,想着能积攒一些换点啥东西,放在服务器上出现了各种错误。
分享一个自动抓取静态站资源的小工具,可以在抓取某个静态站点的时候方便很多,尤其是如果页面比较多的话,会很难受,而且会自动将资源进行归类,如果一个页面一个页面的保存的话,那就比较费劲了。
最近有客户提出了这么一个需求:微信dat文件在解码后的图片无法按照时间进行排序。 是的,解码后的文件的时间都是解码的时间,由于软件比较多,当时没做自动更新,所以在这里做一个小工具,可以将对应的解码后的图片的时间修改为微信dat文件对应的时间
最近一直在围绕着我的小电脑在转,基本都是这方面的问题。在没有公网IP的情况下,这个问题就是我怎么才能通过域名访问到我家中的服务器。
目前了解的有两个模块可以实现二维码的模块,一个是node-qrcode ,这个算是比较大众的,不过环境比较复杂,所以...连看都没看;还有一个是小众的 qr-image ,这个比较简单,没有其他环境依赖,安装即可用,因为要实现一个简单的在线二维码生成,就先用这个试试水了
我们项目一直在使用puppeteer 生成pdf ,整体的思路是没有问题的,而且在开发环境运行了好久了,但是部署后总会有各种各样的报错。各种so文件找不到等等 。