另附:SFTP使用的是linux自带的ssh协议,对linux服务器有要求。sftp的归属目录父级必须为root用户所有,sftp的归属目录中,sftp用户没有操作权限,需要由root用户在此建立一个归属于sftp的目录,在这个目录下,sftp用户才有操作权限。所以调用者在使用目录相关的功能时,一定要考虑目录结构问题,本篇工具类在sftp初始化以后,进行的第一步操作便是由调用者进入其有操作权限的那个目录,sftp.cd('path')
package com.coffer.core.modules.sys.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.coffer.core.common.config.Global;
import com.google.common.base.Strings;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
/**
* @version sftputils
* @author darly
* @date 2020年6月15日15:18:51
*/
public class SFTPUtils {
private static final Log logger = LogFactory.getLog(SFTPUtils.class);;
private static String userName; // SFTP 登录用户名
private static String password; // SFTP 登录密码
private static String ip; // SFTP 服务器地址IP地址
private static int port; // SFTP 端口
/**
* 参数初始化
*/
static boolean init() {
userName = Global.getConfig("fsn.sftp.username");
password = Global.getConfig("fsn.sftp.password");
ip = Global.getConfig("fsn.sftp.hostname");
try {
port = Integer.valueOf(Global.getConfig("fsn.sftp.port"));
if (Strings.isNullOrEmpty(userName) || Strings.isNullOrEmpty(password)
|| Strings.isNullOrEmpty(ip) || port == 0) {
throw new Exception("空参");
}
} catch (Exception e) {
logger.debug("************* FTP初始化异常,请检查参数 **************");
return false;
}
return true;
}
/**
* 获取sftp实例
*
* @return
*/
public static ChannelSftp getInstance() {
if (!init()) {
return null;
}
ChannelSftp sftp = connect(ip, port, userName, password); // 获取连接
return sftp;
}
/**
* 连接sftp服务器
*
* @param host 主机
* @param port 端口
* @param username 用户名
* @param password 密码
* @return
*/
public static ChannelSftp connect(String host, int port, String username, String password) {
ChannelSftp sftp = null;
try {
JSch jsch = new JSch();
// jsch.getSession(username, host, port);
Session sshSession = jsch.getSession(username, host, port);
sshSession.setPassword(password);
Properties sshConfig = new Properties();
sshConfig.put("StrictHostKeyChecking", "no");
sshSession.setConfig(sshConfig);
sshSession.connect();
logger.info("SFTP Session connected.");
Channel channel = sshSession.openChannel("sftp");
channel.connect();
sftp = (ChannelSftp) channel;
logger.info("Connected to " + host);
} catch (Exception e) {
logger.error(e.getMessage());
return null;
}
return sftp;
}
/**
* 上传文件
*
* @param directory 上传的目录
* @param uploadFile 要上传的文件
* 以临时文件tmp形式上传,上传后重命名为正式文件
*/
public static boolean upload(String directory, File uploadFile, ChannelSftp sftp) {
try {
sftp.cd(directory);
FileInputStream fileInputStream = new FileInputStream(uploadFile);
sftp.put(fileInputStream, uploadFile.getName() + ".tmp");
fileInputStream.close();
sftp.rename(uploadFile.getName() + ".tmp", uploadFile.getName());
return true;
} catch (SftpException e) {
// 当进入try中cd目录失败后,接住异常并循环创建目录,创建完成后重新进行文件上传,
// 已经进行多情况验证,不会出现递归循环的情况
if (mkdir(directory, sftp)) {
if (upload(directory, uploadFile, sftp)) {
return true;
}
}
} catch (IOException e) {
e.printStackTrace();
}
logger.debug("**********文件" + uploadFile.getName() + "上传失败**********");
return false;
}
/**
* 下载文件
*
* @param directory 下载目录
* @param downloadFile 下载的文件
* @param saveFile 存在本地的路径
*/
public static File download(String directory, String downloadFile, String saveFile, ChannelSftp sftp) {
FileOutputStream fileOutputStream = null;
try {
File file = new File(saveFile);
fileOutputStream = new FileOutputStream(file);
sftp.cd(directory);
sftp.get(downloadFile, fileOutputStream);
return file;
} catch (Exception e) {
logger.error(e.getMessage());
return null;
} finally {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 删除文件
*
* @param directory 要删除文件所在目录
* @param deleteFile 要删除的文件
*/
public void delete(String directory, String deleteFile, ChannelSftp sftp) {
try {
sftp.cd(directory);
sftp.rm(deleteFile);
} catch (Exception e) {
logger.error(e.getMessage());
}
}
/**
* sftp方式创建目录 可创建多层目录
* 将多层目录按顺序拆分为单层目录组,逐级创建并进入
* 因sftp实例存储目录状态,所以创建完成后,按层级数量后退
* '..'为linux目录的上一层
*
* @param directory
* @param sftp
* @return
*/
public static boolean mkdir(String directory, ChannelSftp sftp) {
try {
logger.debug("**********目录{" + directory + "}不存在,即将创建**********");
String dir[] = directory.split(File.separator);
int i = 0;
for (; i < dir.length; i++) {
try {
sftp.cd(dir[i]);
} catch (Exception e) {
sftp.mkdir(dir[i]);
sftp.cd(dir[i]);
}
}
while (i-- != 0) {
sftp.cd("..");
}
logger.debug("**********目录{" + directory + "}创建完成**********");
return true;
} catch (SftpException e) {
e.printStackTrace();
logger.debug("**********目录{" + directory + "}创建失败**********");
return false;
}
}
/**
* 断开连接
*
* @param sftp
*/
public static void disconnect(ChannelSftp sftp) {
try {
sftp.getSession().disconnect();
} catch (JSchException e) {
logger.error(e.getMessage());
}
sftp.quit();
sftp.disconnect();
}
}