/**
* 文件上传工具
* 支持文件夹上传,单个文件上传
* 上传文件夹时,所在根目录结构必须存在(目录不包含根目录文件夹)
*/
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('下载完成');
// });
// });