|
@@ -0,0 +1,442 @@
|
|
|
+package com.jiayue.passback.util;
|
|
|
+
|
|
|
+import com.jcraft.jsch.*;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.io.IOUtils;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+
|
|
|
+import java.io.*;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.Properties;
|
|
|
+import java.util.Vector;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @description:
|
|
|
+ * @author: 张成龙
|
|
|
+ * @createDate: 2021/9/27
|
|
|
+ * @version: 1.0
|
|
|
+ */
|
|
|
+@Component
|
|
|
+@Slf4j
|
|
|
+public class SFTPUtil {
|
|
|
+
|
|
|
+ private ChannelSftp sftp;
|
|
|
+
|
|
|
+ private Session session;
|
|
|
+
|
|
|
+ // SFTP 登录用户名
|
|
|
+ private String userName;
|
|
|
+ // SFTP 登录密码
|
|
|
+ private String password;
|
|
|
+ // SFTP 服务器地址IP地址
|
|
|
+ private String host;
|
|
|
+ // SFTP 端口
|
|
|
+ private int port;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构造基于密码认证的sftp对象
|
|
|
+ *
|
|
|
+ * @param userName
|
|
|
+ * @param password
|
|
|
+ * @param host
|
|
|
+ * @param port
|
|
|
+ */
|
|
|
+ public SFTPUtil(String userName, String password, String host, int port) {
|
|
|
+ this.userName = userName;
|
|
|
+ this.password = password;
|
|
|
+ this.host = host;
|
|
|
+ this.port = port;
|
|
|
+ }
|
|
|
+
|
|
|
+ public SFTPUtil() {
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 连接sftp服务器
|
|
|
+ *
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public String login(String path) {
|
|
|
+ String fileName = null;
|
|
|
+ try {
|
|
|
+ JSch jsch = new JSch();
|
|
|
+ log.info("sftp连接host:{} username:{}", host, userName);
|
|
|
+
|
|
|
+ session = jsch.getSession(userName, host, port);
|
|
|
+ log.info("Session is build");
|
|
|
+ if (password != null) {
|
|
|
+ session.setPassword(password);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置超时连接50秒
|
|
|
+ session.setTimeout(50000);
|
|
|
+
|
|
|
+ Properties config = new Properties();
|
|
|
+ config.put("StrictHostKeyChecking", "no");
|
|
|
+
|
|
|
+ session.setConfig(config);
|
|
|
+ session.connect();
|
|
|
+ log.info("Session is connected");
|
|
|
+
|
|
|
+ Channel channel = session.openChannel("sftp");
|
|
|
+ channel.connect();
|
|
|
+ log.info("channel is connected");
|
|
|
+
|
|
|
+ sftp = (ChannelSftp) channel;
|
|
|
+ log.info(String.format("sftp server host:[%s] port:[%s] is connect successful", host, port));
|
|
|
+
|
|
|
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
|
|
|
+
|
|
|
+ String date = simpleDateFormat.format(new Date());
|
|
|
+
|
|
|
+ log.info("当天日期为"+date);
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 遍历指定路径
|
|
|
+ Vector<ChannelSftp.LsEntry> fileList = ((ChannelSftp) channel).ls(path);
|
|
|
+ // 获取文件列表
|
|
|
+ for (ChannelSftp.LsEntry entry : fileList) {
|
|
|
+ if (!entry.getAttrs().isDir()) {
|
|
|
+ if (entry.getFilename().contains(date)) {
|
|
|
+ fileName = entry.getFilename();
|
|
|
+ log.info("找到文件"+fileName);
|
|
|
+ }else {
|
|
|
+ log.info("没有找到包含当天日期的文件");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (SftpException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ } catch (JSchException e) {
|
|
|
+ log.error("Cannot connect to specified sftp server : {}:{} \n Exception message is: {}", new Object[]{host, port, e.getMessage()});
|
|
|
+ }
|
|
|
+ return fileName;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 关闭连接 server
|
|
|
+ */
|
|
|
+ public void logout() {
|
|
|
+ if (sftp != null) {
|
|
|
+ if (sftp.isConnected()) {
|
|
|
+ sftp.disconnect();
|
|
|
+ log.info("sftp is closed already");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (session != null) {
|
|
|
+ if (session.isConnected()) {
|
|
|
+ session.disconnect();
|
|
|
+ log.info("sshSession is closed already");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 递归根据路径创建文件夹
|
|
|
+ *
|
|
|
+ * @param dirs 根据 / 分隔后的数组文件夹名称
|
|
|
+ * @param tempPath 拼接路径
|
|
|
+ * @param length 文件夹的格式
|
|
|
+ * @param index 数组下标
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public void mkdirDir(String[] dirs, String tempPath, int length, int index) {
|
|
|
+ // 以"/a/b/c/d"为例按"/"分隔后,第0位是"";顾下标从1开始
|
|
|
+ index++;
|
|
|
+ if (index < length) {
|
|
|
+ // 目录不存在,则创建文件夹
|
|
|
+ tempPath += "/" + dirs[index];
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ log.info("检测目录[" + tempPath + "]");
|
|
|
+ sftp.cd(tempPath);
|
|
|
+ if (index < length) {
|
|
|
+ mkdirDir(dirs, tempPath, length, index);
|
|
|
+ }
|
|
|
+ } catch (SftpException ex) {
|
|
|
+ log.warn("创建目录[" + tempPath + "]");
|
|
|
+ try {
|
|
|
+ sftp.mkdir(tempPath);
|
|
|
+ sftp.cd(tempPath);
|
|
|
+ } catch (SftpException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ log.error("创建目录[" + tempPath + "]失败,异常信息[" + e.getMessage() + "]");
|
|
|
+
|
|
|
+ }
|
|
|
+ log.info("进入目录[" + tempPath + "]");
|
|
|
+ mkdirDir(dirs, tempPath, length, index);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将输入流的数据上传到sftp作为文件(多层目录)
|
|
|
+ *
|
|
|
+ * @param directory 上传到该目录(多层目录)
|
|
|
+ * @param sftpFileName sftp端文件名
|
|
|
+ * @param input 输入流
|
|
|
+ * @throws SftpException
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public void uploadMore(String directory, String sftpFileName, InputStream input) throws SftpException {
|
|
|
+ try {
|
|
|
+ sftp.cd(directory);
|
|
|
+ } catch (SftpException e) {
|
|
|
+ // 目录不存在,则创建文件夹
|
|
|
+ String[] dirs = directory.split("/");
|
|
|
+ String tempPath = "";
|
|
|
+ int index = 0;
|
|
|
+ mkdirDir(dirs, tempPath, dirs.length, index);
|
|
|
+ }
|
|
|
+ sftp.put(input, sftpFileName);// 上传文件
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将输入流的数据上传到sftp作为文件
|
|
|
+ *
|
|
|
+ * @param directory 上传到该目录(单层目录)
|
|
|
+ * @param sftpFileName sftp端文件名
|
|
|
+ * @param input 输入流
|
|
|
+ * @throws SftpException
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public void upload(String directory, String sftpFileName, InputStream input) {
|
|
|
+ try {
|
|
|
+ // 切换路径
|
|
|
+ sftp.cd(directory);
|
|
|
+ } catch (SftpException e) {
|
|
|
+ log.warn(directory + ":directory is not exist");
|
|
|
+ try {
|
|
|
+ // 循环创建路径
|
|
|
+ this.createParentDirectories(sftp, directory);
|
|
|
+ // 切换路径
|
|
|
+ sftp.cd(directory);
|
|
|
+ } catch (SftpException e1) {
|
|
|
+ log.warn("sftp文件路径异常" + e1.toString());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ sftp.put(input, sftpFileName);
|
|
|
+ log.info("file:{} is upload successful", sftpFileName);
|
|
|
+ } catch (SftpException e) {
|
|
|
+ log.warn("文件传输异常" + e.toString());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 上传单个文件
|
|
|
+ *
|
|
|
+ * @param directory 上传到sftp目录
|
|
|
+ * @param uploadFile 要上传的文件,包括路径
|
|
|
+ * @throws FileNotFoundException
|
|
|
+ * @throws SftpException
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public void upload(String directory, String uploadFile) throws FileNotFoundException, SftpException {
|
|
|
+ File file = new File(uploadFile);
|
|
|
+ upload(directory, file.getName(), new FileInputStream(file));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将byte[]上传到sftp,作为文件。注意:从String生成byte[]是,要指定字符集。
|
|
|
+ *
|
|
|
+ * @param directory 上传到sftp目录
|
|
|
+ * @param sftpFileName 文件在sftp端的命名
|
|
|
+ * @param byteArr 要上传的字节数组
|
|
|
+ * @throws SftpException
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public void upload(String directory, String sftpFileName, byte[] byteArr) throws SftpException {
|
|
|
+ upload(directory, sftpFileName, new ByteArrayInputStream(byteArr));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将字符串按照指定的字符编码上传到sftp
|
|
|
+ *
|
|
|
+ * @param directory 上传到sftp目录
|
|
|
+ * @param sftpFileName 文件在sftp端的命名
|
|
|
+ * @param dataStr 待上传的数据
|
|
|
+ * @param charsetName sftp上的文件,按该字符编码保存
|
|
|
+ * @throws UnsupportedEncodingException
|
|
|
+ * @throws SftpException
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public void upload(String directory, String sftpFileName, String dataStr, String charsetName) throws UnsupportedEncodingException, SftpException {
|
|
|
+ upload(directory, sftpFileName, new ByteArrayInputStream(dataStr.getBytes(charsetName)));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 下载文件
|
|
|
+ *
|
|
|
+ * @param directory 下载目录
|
|
|
+ * @param downloadFile 下载的文件
|
|
|
+ * @param saveFile 存在本地的路径
|
|
|
+ * @throws SftpException
|
|
|
+ * @throws FileNotFoundException
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public void download(String directory, String downloadFile, String saveFile) throws SftpException, FileNotFoundException {
|
|
|
+ if (directory != null && !"".equals(directory)) {
|
|
|
+ sftp.cd(directory);
|
|
|
+ log.info("进入"+directory+"目录下");
|
|
|
+ }else {
|
|
|
+ log.info("没有找到指定目录");
|
|
|
+ }
|
|
|
+ FileOutputStream fos = null;
|
|
|
+ try {
|
|
|
+ fos = new FileOutputStream(saveFile);
|
|
|
+ sftp.get(downloadFile, fos);
|
|
|
+ log.info("file:{} 文件下载成功!", downloadFile);
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 处理异常
|
|
|
+ log.error("文件下载失败", e);
|
|
|
+ throw e;
|
|
|
+ } finally {
|
|
|
+ if (fos != null) {
|
|
|
+ try {
|
|
|
+ fos.close();
|
|
|
+ } catch (IOException e) {
|
|
|
+ // 记录关闭流时的异常
|
|
|
+ log.error("关闭文件输出流时发生异常", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 下载文件
|
|
|
+ *
|
|
|
+ * @param directory 下载目录
|
|
|
+ * @param downloadFile 下载的文件名
|
|
|
+ * @return 字节数组
|
|
|
+ * @throws SftpException
|
|
|
+ * @throws IOException
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public byte[] download(String directory, String downloadFile) throws SftpException, IOException {
|
|
|
+ if (directory != null && !"".equals(directory)) {
|
|
|
+ sftp.cd(directory);
|
|
|
+ }
|
|
|
+ InputStream is = sftp.get(downloadFile);
|
|
|
+ byte[] fileData = IOUtils.toByteArray(is);
|
|
|
+ log.info("file:{} is download successful", downloadFile);
|
|
|
+ return fileData;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 删除文件
|
|
|
+ *
|
|
|
+ * @param directory 要删除文件所在目录
|
|
|
+ * @param deleteFile 要删除的文件
|
|
|
+ * @throws SftpException
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public void delete(String directory, String deleteFile) throws SftpException {
|
|
|
+ sftp.cd(directory);
|
|
|
+ sftp.rm(deleteFile);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 列出目录下的文件
|
|
|
+ *
|
|
|
+ * @param directory 要列出的目录
|
|
|
+ * @return
|
|
|
+ * @throws SftpException
|
|
|
+ */
|
|
|
+ public Vector<?> listFiles(String directory) throws SftpException {
|
|
|
+ return sftp.ls(directory);
|
|
|
+ }
|
|
|
+
|
|
|
+// public static void main(String[] args) throws SftpException, IOException {
|
|
|
+// SFTPUtil sftp = new SFTPUtil("jyzx2023", "hH6*7E$h", "114.115.165.178", 22);
|
|
|
+// sftp.login();
|
|
|
+// File file = new File("..\\sftp测试.txt");
|
|
|
+// log.info(System.getProperty("user.dir"));
|
|
|
+// InputStream is = new FileInputStream(file);
|
|
|
+// // 多级目录创建并上传
|
|
|
+// sftp.upload("/subdata/20230712/real", "sftp测试.txt", is);
|
|
|
+// sftp.logout();
|
|
|
+// }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 多级目录创建并上传
|
|
|
+ * @param userName
|
|
|
+ * @param password
|
|
|
+ * @param host
|
|
|
+ * @param port
|
|
|
+ * @param file
|
|
|
+ * @throws SftpException
|
|
|
+ * @throws FileNotFoundException
|
|
|
+ */
|
|
|
+// public void uploadByFileAndPath(String userName, String password, String host, int port, File file, String sftpFilePath, String fileName) {
|
|
|
+// SFTPUtil sftp = new SFTPUtil(userName, password, host, port);
|
|
|
+// sftp.login();
|
|
|
+// log.info(System.getProperty("user.dir"));
|
|
|
+// try {
|
|
|
+// InputStream is = new FileInputStream(file);
|
|
|
+// // 多级目录创建并上传
|
|
|
+// sftp.upload(sftpFilePath, fileName, is);
|
|
|
+// } catch (FileNotFoundException e) {
|
|
|
+// e.printStackTrace();
|
|
|
+// }
|
|
|
+// sftp.logout();
|
|
|
+// }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 登录并下载所需文件
|
|
|
+ *
|
|
|
+ * @param userName
|
|
|
+ * @param password
|
|
|
+ * @param host
|
|
|
+ * @param port
|
|
|
+ * @param sftpFilePath
|
|
|
+ */
|
|
|
+ public static void loginAndDownload(String userName, String password, String host, int port, String sftpFilePath,String savePath) {
|
|
|
+ SFTPUtil sftp = new SFTPUtil(userName, password, host, port);
|
|
|
+
|
|
|
+ String fileName = sftp.login(sftpFilePath);
|
|
|
+
|
|
|
+ try {
|
|
|
+ if (null != fileName) {
|
|
|
+ // 下载文件
|
|
|
+ sftp.download(sftpFilePath, fileName, savePath+File.separator+fileName);
|
|
|
+ } else {
|
|
|
+ log.error("没有找到所需文件");
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ sftp.logout();
|
|
|
+ log.info("下载完成关闭断开Sftp");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 循环创建路径
|
|
|
+ *
|
|
|
+ * @param sftpChannel
|
|
|
+ * @param directory
|
|
|
+ */
|
|
|
+ private static void createParentDirectories(ChannelSftp sftpChannel, String directory) {
|
|
|
+ String[] directories = directory.split("/");
|
|
|
+ String parentDirectory = "";
|
|
|
+
|
|
|
+ for (String dir : directories) {
|
|
|
+ if (!dir.isEmpty()) {
|
|
|
+ parentDirectory += "/" + dir;
|
|
|
+ try {
|
|
|
+ sftpChannel.mkdir(parentDirectory);
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 目录已存在,忽略异常
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ log.info("创建路径:" + parentDirectory);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|