node ftp上傳文件夾到服務(wù)器案例詳解
完整代碼示例如下:
const ftp = require('ftp');//連接FTP
const path = require('path');
const client = new ftp();
const fs = require('fs');
//本地文件夾路徑;
const localDirPath = '/test/';
//遠(yuǎn)程地址,打開ftp以后的地址,不需要加入host;
const remotePath = '/';
const uploadFiles = [];
const mkDirPromiseArr = [];
const connectionProperties = {
host: '', //ftp地址;
user: '', //用戶名;
password: '', //密碼;
port: 21 //端口;
};
client.connect(connectionProperties);
client.on('ready', () => {
console.log('ftp client is ready');
start();
});
async function start() {
const { err: ea, dir } = await cwd(remotePath);//此處應(yīng)對(duì)err做處理
if (ea) {
client.mkdir(remotePath, true, (err) => {
if (err) {
console.log('創(chuàng)建' + remotePath + '文件夾失敗');
upload();
} else {
console.log('創(chuàng)建' + remotePath + '成功');
upload();
}
});
} else {
upload();
}
function upload() {
const filesPath = { files: [] };
getDirAllFilePath(localDirPath, filesPath);
remoteMkDir(filesPath, '');
console.log('準(zhǔn)備上傳...');
setTimeout(() => {
Promise.all(mkDirPromiseArr).then(() => {
console.log('開始上傳...');
const tasks = uploadFile();
runPromiseArray(tasks).then(() => {
client.end();
console.warn('上傳完成~');
});
});
}, 3000);
}
}
// 獲取本地的文件地址和路徑;
function getDirAllFilePath(paths, parent) {
const files = fs.readdirSync(paths);
files.forEach(item => {
if (item != '.DS_Store') {
const path = `${paths}/${item}`;
if (isDir(path)) {
getDirAllFilePath(path, parent[item] = { files: [] });
} else if (isFile(path)) {
parent.files.push(item);
}
}
})
}
//創(chuàng)建遠(yuǎn)程確實(shí)的文件夾;
async function remoteMkDir(obj, _path) {
for (const key in obj) {
if (key === 'files') {
for (let i = 0, len = obj[key].length; i < len; i++) {
const promise = new Promise(async resolve => {
let p = '';
if (_path) {
p = _path + '/';
}
const filePathName = p + obj[key][i];
uploadFiles.push({ path: filePathName, fileName: obj[key][i] });
const ph = remotePath + filePathName.substring(0, filePathName.lastIndexOf('/') + 1);
let { err: ea, dir } = await cwd(ph);//此處應(yīng)對(duì)err做處理
if (ea) {
client.mkdir(ph, true, (err) => {
if (err) {
console.log('mkdir' + ph + 'err', err);
resolve(null);
return;
}
console.log('mkdir ' + ph + ' success');
resolve(null);
});
} else {
resolve(null);
}
});
mkDirPromiseArr.push(promise);
}
} else {
let p = '';
if (_path) {
p = _path + '/';
}
remoteMkDir(obj[key], p + key);
}
}
}
//上傳文件;
function uploadFile() {
const tasks = [];
const resourcesPath = localDirPath;
//目標(biāo)路徑文件夾;
const checkPath = remotePath;
for (let i = 0, len = uploadFiles.length; i < len; i++) {
const task = () => {
return new Promise(async (resolve, reject) => {
const _path = uploadFiles[i].path;
const targetPath = checkPath + _path;
const putPath = resourcesPath + '/' + _path;
const dirpath = path.dirname(targetPath);
const fileName = path.basename(targetPath);
client.cwd(dirpath, (cwdErr, dir) => {
client.pwd((pwdErr, cwd) => {
if (pwdErr) {
resolve(pwdErr)
} else {
client.get(fileName, (err, res) => {
if (res) {
console.log(`${targetPath} =====================已經(jīng)存在了`);
resolve(true);
} else {
const rs = fs.createReadStream(putPath);
client.put(rs, fileName, (putErr, data) => {
if (putErr) {
resolve(err);
} else {
console.log(targetPath + '文件上傳成功');
resolve(true);
}
})
}
});
}
});
})
});
}
tasks.push(task);
}
return tasks;
}
//執(zhí)行Promise的隊(duì)列動(dòng)作;
function runPromiseArray(parray) { //這個(gè)方法可以放到G里
let p = Promise.resolve();
for (let promise of parray) {
p = p.then(promise);
}
return p;
}
//切換目錄
async function cwd(dirpath) {
return new Promise((resolve, reject) => {
client.cwd(dirpath, (err, dir) => {
resolve({ err: err, dir: dir });
})
});
}
function isFile(filepath) { //判斷是否是文件 Boolean
let stat = fs.statSync(filepath)
return stat.isFile()
}
function isDir(filepath) { //判斷是否是文件夾 Boolean
let stat = fs.statSync(filepath);
return stat.isDirectory();
}
筆者解讀一下:代碼中的localDirPath為本地需要讀取其中文件,并使用ftp上傳的文件夾。
注意:這里的上傳是針對(duì)文件夾中所有的文件夾與文件進(jìn)行遍歷后的上傳,實(shí)際應(yīng)用中,我們可能只需要上傳指定的文件,對(duì)此,筆者修改后的腳本如下:
const ftp = require('ftp');//連接FTP
const path = require('path');
const client = new ftp();
const fs = require('fs');
//本地文件夾路徑;
const localDirPath = path.join(__dirname,'/imgtmp/');//待遍歷的本地目錄
//遠(yuǎn)程ftp服務(wù)器文件路徑
let remotePath = '/yourweb/images/';
const upFileList = ["202304/202304061415075072.png","202304/202304061415075073.png"];//手動(dòng)設(shè)置需要上傳的文件
const uploadFiles = [];
const mkDirPromiseArr = [];
client.on('ready',()=>{
console.log('ftp client is ready');
});
const connconfig = {
host: '', //ftp地址;
user: '', //用戶名;
password: '', //密碼;
port: 21 //端口;
}
client.connect(connconfig);
client.on('ready', () => {
console.log('ftp client is ready');
start();
});
async function start() {
const { err: ea, dir } = await cwd(remotePath);//此處應(yīng)對(duì)err做處理
if (ea) {
client.mkdir(remotePath, true, (err) => {
if (err) {
console.log('創(chuàng)建' + remotePath + '文件夾失敗');
upload();
} else {
console.log('創(chuàng)建' + remotePath + '成功');
upload();
}
});
} else {
upload();
}
function upload() {
console.log("mkDirPromiseArr==>",mkDirPromiseArr);
// const filesPath = { files: [] };
// getDirAllFilePath(localDirPath, filesPath);
const filesPath = { files: upFileList };//直接給定需要上傳的文件列表
// console.log("遍歷之后的filesPath===>",filesPath);
remoteMkDir(filesPath, '');
console.log('準(zhǔn)備上傳...');
setTimeout(() => {
Promise.all(mkDirPromiseArr).then(() => {
console.log('開始上傳...');
const tasks = uploadFile();
runPromiseArray(tasks).then(() => {
client.end();
console.warn('上傳完成~');
});
});
}, 1000);
}
}
// 獲取本地的文件地址和路徑;
function getDirAllFilePath(paths, parent) {
const files = fs.readdirSync(paths);
files.forEach(item => {
if (item != '.DS_Store') {
const path = `${paths}/${item}`;
if (isDir(path)) {
getDirAllFilePath(path, parent[item] = { files: [] });
} else if (isFile(path)) {
parent.files.push(item);
}
}
})
}
//創(chuàng)建遠(yuǎn)程缺失的文件夾;
async function remoteMkDir(obj, _path) {
for (const key in obj) {
if (key === 'files') {
for (let i = 0, len = obj[key].length; i < len; i++) {
const promise = new Promise(async resolve => {
let p = '';
if (_path) {
p = _path + '/';
}
const filePathName = p + obj[key][i];
// const filePathName = path.dirname(obj[key][i]);
const fileName = path.basename(obj[key][i]);
// uploadFiles.push({ path: filePathName, fileName: obj[key][i] });
uploadFiles.push({ path: filePathName, fileName: fileName });
const ph = remotePath + filePathName.substring(0, filePathName.lastIndexOf('/') + 1);
let { err: ea, dir } = await cwd(ph);//此處應(yīng)對(duì)err做處理
if (ea) {
client.mkdir(ph, true, (err) => {
if (err) {
console.log('mkdir' + ph + 'err', err);
resolve(null);
return;
}
console.log('mkdir ' + ph + ' success');
resolve(null);
});
} else {
resolve(null);
}
});
mkDirPromiseArr.push(promise);
}
} else {
let p = '';
if (_path) {
p = _path + '/';
}
remoteMkDir(obj[key], p + key);
}
}
}
//上傳文件;
function uploadFile() {
const tasks = [];
const resourcesPath = localDirPath;
//目標(biāo)路徑文件夾;
const checkPath = remotePath;
for (let i = 0, len = uploadFiles.length; i < len; i++) {
const task = () => {
return new Promise(async (resolve, reject) => {
const _path = uploadFiles[i].path;
// const _path = uploadFiles[i];
const targetPath = checkPath + _path;
const putPath = resourcesPath + '/' + _path;
const dirpath = path.dirname(targetPath);
const fileName = path.basename(targetPath);
client.cwd(dirpath, (cwdErr, dir) => {
client.pwd((pwdErr, cwd) => {
if (pwdErr) {
resolve(pwdErr)
} else {
client.get(fileName, (err, res) => {
if (res) {
console.log(`${targetPath} =====================已經(jīng)存在了`);
resolve(true);
} else {
const rs = fs.createReadStream(putPath);
client.put(rs, fileName, (putErr, data) => {
if (putErr) {
resolve(err);
} else {
console.log(targetPath + '文件上傳成功');
resolve(true);
}
})
}
});
}
});
})
});
}
tasks.push(task);
}
return tasks;
}
//執(zhí)行Promise的隊(duì)列動(dòng)作;
function runPromiseArray(parray) { //這個(gè)方法可以放到G里
let p = Promise.resolve();
for (let promise of parray) {
p = p.then(promise);
}
return p;
}
//切換目錄
async function cwd(dirpath) {
return new Promise((resolve, reject) => {
client.cwd(dirpath, (err, dir) => {
resolve({ err: err, dir: dir });
})
});
}
function isFile(filepath) { //判斷是否是文件 Boolean
let stat = fs.statSync(filepath)
return stat.isFile()
}
function isDir(filepath) { //判斷是否是文件夾 Boolean
let stat = fs.statSync(filepath);
return stat.isDirectory();
}PS:筆者此處使用了一個(gè)upFileList數(shù)組保存了需要上傳到服務(wù)器的圖片文件路徑(包括文件夾與文件名),感興趣的朋友可以測(cè)試一下看看效果~
相關(guān)文章
Node.js版本升級(jí)如何修改模塊默認(rèn)的保存位置
這篇文章主要給大家介紹了關(guān)于Node.js版本升級(jí)如何修改模塊默認(rèn)的保存位置,文中通過(guò)代碼以及圖文介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用node.js具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-05-05
Node.js數(shù)據(jù)庫(kù)操作之查詢MySQL數(shù)據(jù)庫(kù)(二)
這篇文章主要介紹了Node.js數(shù)據(jù)庫(kù)操作之查詢MySQL數(shù)據(jù)庫(kù)的相關(guān)資料,文中介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用mysql能帶來(lái)一定的幫助,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-03-03
Node.js fs模塊(文件模塊)創(chuàng)建、刪除目錄(文件)讀取寫入文件流的方法
這篇文章主要介紹了Node.js fs模塊(文件模塊)創(chuàng)建、刪除目錄(文件)讀取寫入文件流的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09
Node.js實(shí)戰(zhàn)之Buffer和Stream模塊系統(tǒng)深入剖析詳解
這篇文章主要介紹了Node.js實(shí)戰(zhàn)之Buffer和Stream模塊系統(tǒng)深入剖析詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
node.js中實(shí)現(xiàn)雙重身份驗(yàn)證機(jī)制的方法詳解
雙重身份驗(yàn)證(Two-factor?authentication)是一種安全機(jī)制,它要求用戶提供兩種不同的身份驗(yàn)證因素來(lái)訪問(wèn)他們的帳戶,下面我們就來(lái)學(xué)習(xí)一下如何使用speakeasy在nodejs中實(shí)現(xiàn)雙重身份驗(yàn)證吧2023-10-10
nodejs更新package.json中的dependencies依賴到最新版本的方法
今天小編就為大家分享一篇nodejs更新package.json中的dependencies依賴到最新版本的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-10-10
Node如何實(shí)現(xiàn)在瀏覽器預(yù)覽項(xiàng)目的所有圖片詳解
最近項(xiàng)目遇到了個(gè)需求,需要將存放圖片進(jìn)行預(yù)覽,所以這篇文章主要給大家介紹了關(guān)于Node如何實(shí)現(xiàn)在瀏覽器預(yù)覽項(xiàng)目的所有圖片的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01
nodejs 實(shí)現(xiàn)釘釘ISV接入的加密解密方法
這篇文章主要介紹了nodejs 實(shí)現(xiàn)釘釘ISV接入的加密解密方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的的朋友參考下吧,需要的朋友可以參考下2017-01-01

