ftp 文件夹/单个文件 上传 及下载

/**
 * 文件上传工具
 * 支持文件夹上传,单个文件上传
 * 上传文件夹时,所在根目录结构必须存在(目录不包含根目录文件夹)
 */

const ftp = require("ftp");
const path = require("path");
const fs = require("fs");

const client = new ftp();
client.on("ready", () => {
    console.log(new Date());
    console.log("ftp client is ready");
});

client.on("close", () => {
    console.log(new Date());
    console.log("ftp client has close");
});

client.on("end", () => {
    console.log(new Date());
    console.log("ftp client has end");
});

client.on("error", (err) => {
    console.log(new Date());
    console.log("ftp client has an error", JSON.stringify(err));
    client.end();
});

client.connect({
    host: "127.0.0.1",
    port: 80,
    user: "123123",
    password: "123123",
    keepalive: 1000
});

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

// 返回至指定根目录
function bwd(dirpath){
    let len = (dirpath.split("/")).length + 1;
    let str = "../".repeat(len);
    return new Promise((resolve, reject) => {
        client.cwd(str, (err, dir) => {
            resolve({err, dir});
        });
    })
}

// 将文件上传到ftp目标地址
async function putsingleFile(currentFile, targetFilePath){
    currentFile = currentFile.replace(/\\/g, "/");
    // console.log("上传文件地址", currentFile);
    // console.log('目标文件地址', targetFilePath);
    const dirpath = path.dirname(targetFilePath);
    const fileName = path.basename(targetFilePath);
    const rs = fs.createReadStream(currentFile);
    let {err: ea, dir} = await cwd(dirpath);
    if(ea){
        return Promise.resolve({err: ea});
    }
    return new Promise((resolve, reject)=>{
        client.put(rs, fileName, (err)=>{
            resolve({err});
        });
    });
}

// 创建远程目录
function create(dirPath){
    return new Promise((resolve, reject) => {
        client.mkdir(dirPath, true, (err)=>{
            if(err){
                console.warn("文件夹创建已存在");
            }
            resolve();
        });
    });
}

// 删除远程目录
function deleteDir(targetFilePath){
    return new Promise((resolve, reject) => {
        console.log('移除远程目录', targetFilePath);
        client.rmdir(targetFilePath, true, (err) => {
            if(err){
                console.warn("待移除文件夹不存在");
            }
            resolve();
        });
    });
}

// 延时器 毫秒
function sleep(time){
    console.log("延时:", time);
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve();
        }, time);
    });
}

// 上传文件夹
async function putDir(currentFile, targetFilePath){
    let allFiles = [];
    let allDirs = [];
    // console.log("目标文件夹:", currentFile);
    // console.log("远程文件夹:", targetFilePath);
    await deleteDir(targetFilePath);
    await create(targetFilePath);
    loopDirs(targetFilePath, currentFile, allFiles, allDirs);
    console.log('文件夹遍历成功', allDirs.length);
    for(const dir of allDirs){
        await create(dir);
    }
    console.log("文件夹创建成功");
    await sleep(1000);
    
    let index = 0;
    for(const file of allFiles){
        // console.log("开始上传文件 ", file);
        let tartget = file.replace(/\\/g,"/");
        currentFile = currentFile.replace(/\\/g,"/");
        let targetPath = tartget.replace(currentFile, targetFilePath);
        targetPath = targetPath.replace(/\\/g,"/");
        let {err: eb} = await putsingleFile(file, targetPath);
        if(eb){
            console.log(eb);
            continue ;
        }
        else{
            // console.log("上传文件成功 ", file);
            index++;
            console.log("当前上传进度 ", index, "/", allFiles.length);
        }

        const dirpath = path.dirname(targetPath);
        await bwd(dirpath);
    }
    console.log("文件夹上传成功");
    return Promise.resolve();
}

// 循环遍历本地文件夹,及待上传文件
const loopDirs = function (remote, dir, arr, dirArr) {
    let files = fs.readdirSync(dir);  // 遍历当前文件夹下所有文件
    for (let file of files) {
      if (file.indexOf(".git") >= 0 || file.indexOf(".svn") >= 0 || file.indexOf('gitignore') > 0) {
        continue;
      }
      let fullpath = path.join(dir, file);
      let stat = fs.statSync(fullpath);
      if (stat.isFile()) {
        arr.push(fullpath);
      } else if (stat.isDirectory()) {
          let dirPath = path.join(remote, file);
          dirPath = dirPath.replace(/\\/g,"\/");
          if(dirArr.indexOf(dirPath) === -1){
            dirArr.push(dirPath);
          }
        loopDirs(remote + "/" + file, fullpath, arr, dirArr);
      }
    }
  }

// 下载远程zip文件
async function downloadFile(remote, locate){
    return new Promise((resolve, reject)=>{
        client.get(remote, (err, streamData)=>{
            if(err){
                console.log("下载失败");
            }
            streamData.pipe(fs.createWriteStream(locate)).end(()=>{
                resolve();
            });
        });
    });
    
}

let fileUpload = async function(type, local, remote){
    // remote = "test/" + remote;
    if(type === "single"){
        console.log("文件开始上传单个文件", local);
        let {err: eb} = await putsingleFile(local, remote);
        if(eb){
            console.log(eb);
            return ;
        }
        let {err: ea, dir} = await bwd(remote);
        if(ea){
            console.log(ea);
            return ;
        }
    }
    else if(type === "dir"){
        console.log("文件开始上传文件夹");
        await putDir(local, remote);
    }
    else if(type === "downloadZip"){
        await downloadFile(remote, local);
    }
    else if(type === "end"){
        client.end();
        console.log("文件上传成功: ", new Date());
    }

    return Promise.resolve();
}

module.exports = fileUpload;

// 测试用例
// androidUpload("E:/XXXX", "[root]/XXXX", "dir");
// putDir("E:/XXX", "[root]/XXXX");
// client.get("[root]/xxx.zip", (err, streamData)=>{
//     if(err){
//         console.log("下载失败");
//     }
//     streamData.pipe(fs.createWriteStream("E:/XXXX.zip")).end(()=>{
//         client.end();
//         console.log('下载完成');
//     });
// });

你可能感兴趣的:(NodeJs,ftp,node.js)