阅读量:1
1、使用jsch
<!--sftp文件上传--> <dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.55</version> </dependency>
2、配置类
package com.base.jsch; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; @Data @Component @ConfigurationProperties(prefix = "sftp") public class SFTPConfig { /** * SFTP 服务器地址IP地址 */ @NotBlank(message = "IP地址不能为空") private String ip; /** * SFTP 端口 */ @NotNull(message = "端口不能为空") private int port; /** * SFTP 登录用户名 */ @NotBlank(message = "用户名不能为空") private String username; /** * SFTP 登录密码 */ @NotBlank(message = "密码不能为空") private String password; /** * SFTP 私钥 */ private String privateKey; /** * 上传失败隔多长时间重新上传 */ @NotNull(message = "上传失败重试间隔不能为空") private int uploadSleep; /** * 重新上传的次数 */ @NotNull(message = "重新上传次数不能为空") private int uploadRetry; /** * 服务器路径 */ @NotBlank(message = "服务器路径不能为空") private String serverStorageDir; @NotNull(message = "文件名是否需要中文编码") private Boolean isFileNameGBK; }
3、获取连接
package com.base.jsch; import java.lang.reflect.Field; import java.util.Properties; import com.jcraft.jsch.*; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * SFTP工厂类,用于获取SFTP的连接和关闭SFTP的连接 */ @Slf4j @Component public class SFTPConnection { @Autowired private SFTPConfig sftpConfig; private static ChannelSftp client; private static Session session; /** * 建立连接 * * @return client */ public synchronized ChannelSftp makeConnection() { if (client == null || session == null || !client.isConnected() || !session.isConnected()) { try { JSch jsch = new JSch(); if (sftpConfig.getPrivateKey() != null) { jsch.addIdentity(sftpConfig.getPrivateKey());// 设置私钥 } session = jsch.getSession(sftpConfig.getUsername(), sftpConfig.getIp(), sftpConfig.getPort()); if (sftpConfig.getPassword() != null) { session.setPassword(sftpConfig.getPassword()); } Properties config = new Properties(); config.put("StrictHostKeyChecking", "no"); session.setConfig(config); session.connect(); client = (ChannelSftp)session.openChannel("sftp"); client.connect(); log.info("sftp服务器连接成功"); // 文件名中文乱码 if(Boolean.TRUE.equals(sftpConfig.getIsFileNameGBK())){ try{ Class<ChannelSftp> cl = ChannelSftp.class; Field f1 =cl.getDeclaredField("server_version"); f1.setAccessible(true); f1.set(client, 2); client.setFilenameEncoding("gbk"); log.info("设置中文编码"); }catch (NoSuchFieldException | SftpException | IllegalAccessException e) { log.error("设置中文编码" + e.getMessage()); throw new RuntimeException(e); } } } catch (JSchException e) { log.error("主机sftp登录失败,检测登录ip,端口号,用户名密码是否正确,错误信息为" + e.getMessage()); } } return client; } /** * 关闭连接 */ public void logout() { if (client != null) { if (client.isConnected()) { client.disconnect(); } } if (session != null) { if (session.isConnected()) { session.disconnect(); } } } }
4、上传工具类
package com.base.jsch; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.concurrent.TimeUnit; import com.jcraft.jsch.SftpATTRS; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.SftpException; /** * 工具类 */ @Slf4j @Component public class SFTPClientUtils { @Autowired private SFTPConfig sftpConfig; @Autowired private SFTPConnection sftpConnection; public synchronized boolean upload(InputStream fileIs, String fileName) { boolean result = false; int i = 0; while (!result) { log.info("*****开始登陆*****"); ChannelSftp sftp = sftpConnection.makeConnection(); if(null == sftp || !sftp.isConnected() || sftp.isClosed()){ log.info("连接无效"); return result; } log.info("******登陆成功*****"); try { sftp.cd(sftpConfig.getServerStorageDir()); } catch (SftpException e) { if(sftp.isConnected()){ log.info("sftp文件上传,目录不存在开始创建"); try { sftp.mkdir(sftpConfig.getServerStorageDir()); sftp.cd(sftpConfig.getServerStorageDir()); } catch (SftpException e1) { log.info("sftp文件上传,目录创建失败,错误信息:" + e1.fillInStackTrace()); } }else{ log.info("sftp连接已经失效"); return result; } } try { sftp.put(fileIs, fileName, new FileProgressMonitor(fileIs.available()), ChannelSftp.OVERWRITE); // 用下面的方法不会调用进度监控 //sftp.put(fileIs, fileName); if (i > 0) { log.info("sftp重试文件上传成功,ftp路径:" + sftpConfig.getServerStorageDir() + ",文件名称:" + fileName); } else { log.info("sftp文件上传成功,ftp路径为" + sftpConfig.getServerStorageDir() + ",文件名称:" + fileName); } result = true; } catch (Exception e) { i++; log.error("sftp文件上传失败,重试中。。。第" + i + "次,错误信息" + e.fillInStackTrace()); if (i > sftpConfig.getUploadRetry()) { sftpConnection.logout(); log.error("sftp文件上传失败,超过重试次数结束重试,错误信息" + e.fillInStackTrace()); return result; } try { TimeUnit.MILLISECONDS.sleep(sftpConfig.getUploadSleep()); } catch (InterruptedException e1) { sftpConnection.logout(); e1.printStackTrace(); log.error("sftp文件上传失败,系统检测出异常:" + e); } } } sftpConnection.logout(); log.info("sftp上传:" + result); try { fileIs.close(); } catch (IOException e) { throw new RuntimeException(e); } return result; } public synchronized void download(String directory, String downloadFile, String localDir) { log.info("*****开始登陆*****"); ChannelSftp sftp = sftpConnection.makeConnection(); log.info("******登陆成功*****"); if (directory != null && !"".equals(directory)) { try { sftp.cd(directory); } catch (SftpException e) { log.error("sftp文件下载,目录不存在,错误信息" + e.fillInStackTrace()); } } String src = directory + "/" + downloadFile; try { SftpATTRS attr = sftp.stat(src); long fileSize = attr.getSize(); InputStream inputStream = sftp.get(src, new FileProgressMonitor(fileSize)); // 用下面的方法不会调用进度监控 //InputStream inputStream = sftp.get(src); String tempFile = localDir + "/" + downloadFile; File file = new File(tempFile); File fileParent = file.getParentFile(); if (!fileParent.exists()) { fileParent.mkdirs(); } if (!file.exists()) { writeToLocal(tempFile, inputStream); } } catch (SftpException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } sftpConnection.logout(); } // /** // * 文件上传 将文件对象上传到sftp作为文件。文件完整路径=basePath+directory 目录不存在则会上传文件夹 // * // * @param basePath 服务器的基础路径,服务器上必须有该目录,例如 /home // * @param directory 上传到的目录,服务器上没有会自动创建,有则不创建,例如 /test // * @param fileIs 文件流 // * @param fileName 放到服务器上要保存的名字,例如 码海无际.txt // * @return // */ // public synchronized static boolean upload(String basePath, String directory, InputStream fileIs, String fileName) { // boolean result = false; // Integer i = 0; // while (!result) { // log.info("*****开始登陆*****"); // ChannelSftp sftp = SFTPConnectionFactory.makeConnection(); // log.info("******登陆成功*****"); // try { // sftp.cd(basePath); // sftp.cd(directory); // } catch (SftpException e) { // log.info("sftp文件上传,目录不存在开始创建"); // String[] dirs = directory.split("/"); // String tempPath = basePath; // for (String dir : dirs) { // if (null == dir || "".equals(dir)) { // continue; // } // tempPath += "/" + dir; // try { // sftp.cd(tempPath); // } catch (SftpException ex) { // try { // sftp.mkdir(tempPath); // sftp.cd(tempPath); // } catch (SftpException e1) { // log.info("sftp文件上传,目录创建失败,错误信息:" + e1.fillInStackTrace()); // } // } // } // } // try { // sftp.put(fileIs, fileName, new FileProgressMonitor(fileIs.available()), ChannelSftp.OVERWRITE); // // 用下面的方法不会调用进度监控 // //sftp.put(fileIs, fileName); // if (i > 0) { // log.info("sftp重试文件上传成功,ftp路径:" + basePath + directory + ",文件名称:" + fileName); // } else { // log.info("sftp文件上传成功,ftp路径为" + basePath + directory + ",文件名称:" + fileName); // } // result = true; // } catch (Exception e) { // i++; // log.error("sftp文件上传失败,重试中。。。第" + i + "次,错误信息" + e.fillInStackTrace()); // if (i > uploadRettry) { // SFTPConnectionFactory.logout(); // log.error("sftp文件上传失败,超过重试次数结束重试,错误信息" + e.fillInStackTrace()); // return result; // } // try { // TimeUnit.MILLISECONDS.sleep(uploadSleep); // } catch (InterruptedException e1) { // SFTPConnectionFactory.logout(); // e1.printStackTrace(); // log.error("sftp文件上传失败,系统检测出异常:" + e); // } // } // // } // SFTPConnectionFactory.logout(); // log.info("sftp上传:" + result); // try { // fileIs.close(); // } catch (IOException e) { // throw new RuntimeException(e); // } // return result; // } // /** // * 下载文件至本地 // * // * @param directory 要下载文件所在目录,例如 /home // * @param downloadFile 要下载的文件,例如 码海无际.txt // * @param localDir 本地路径,例如 D:\\home // * @return // */ // public synchronized static void download(String directory, String downloadFile, String localDir) { // log.info("*****开始登陆*****"); // ChannelSftp sftp = SFTPConnectionFactory.makeConnection(); // log.info("******登陆成功*****"); // if (directory != null && !"".equals(directory)) { // try { // sftp.cd(directory); // } catch (SftpException e) { // log.error("sftp文件下载,目录不存在,错误信息" + e.fillInStackTrace()); // } // } // String src = directory + "/" + downloadFile; // try { // SftpATTRS attr = sftp.stat(src); // long fileSize = attr.getSize(); // InputStream inputStream = sftp.get(src, new FileProgressMonitor(fileSize)); // // 用下面的方法不会调用进度监控 // //InputStream inputStream = sftp.get(src); // String tempFile = localDir + "/" + downloadFile; // File file = new File(tempFile); // File fileParent = file.getParentFile(); // if (!fileParent.exists()) { // fileParent.mkdirs(); // } // if (!file.exists()) { // writeToLocal(tempFile, inputStream); // } // } catch (SftpException e) { // e.printStackTrace(); // } catch (IOException e) { // e.printStackTrace(); // } // SFTPConnectionFactory.logout(); // } /** * 将InputStream写入本地文件 * * @param destination 写入本地目录 * @param input 输入流 * @throws IOException 异常 */ public static void writeToLocal(String destination, InputStream input) throws IOException { int index; byte[] bytes = new byte[1024]; FileOutputStream downloadFile = new FileOutputStream(destination); while ((index = input.read(bytes)) != -1) { downloadFile.write(bytes, 0, index); downloadFile.flush(); } downloadFile.close(); input.close(); } /** * 删除文件 * * @param directory 要删除文件所在目录,例如 /home * @param deleteFile 要删除的文件,例如 码海无际.txt */ public synchronized boolean delete(String directory, String deleteFile) { boolean result = false; ChannelSftp sftp = sftpConnection.makeConnection(); try { sftp.cd(directory); sftp.rm(deleteFile); } catch (SftpException e) { e.printStackTrace(); } result = true; sftpConnection.logout(); return result; } }
5、上传进度
package com.base.jsch; import com.jcraft.jsch.SftpProgressMonitor; import lombok.extern.slf4j.Slf4j; import java.text.DecimalFormat; @Slf4j public class FileProgressMonitor implements SftpProgressMonitor { private long fileSize; // 记录文件总大小 private long transfered; // 记录已传输的数据总大小 public FileProgressMonitor(long fileSize) { if (fileSize != 0) { this.fileSize = fileSize; log.info("数据大小: " + fileSize + " bytes"); } else { log.info("文件错误"); } } @Override public void init(int op, String src, String dest, long max) { log.info("开始"); } /** * 实现了SftpProgressMonitor接口的count方法 */ @Override public boolean count(long count) { add(count); return true; } /** * 实现了SftpProgressMonitor接口的end方法 */ @Override public void end() { log.info("结束"); } private synchronized void add(long count) { transfered = transfered + count; log.info("已传输数据大小: " + transfered + " bytes"); double d = ((double) transfered * 100) / (double) fileSize; DecimalFormat df = new DecimalFormat("#.##"); log.info("已传输数据占比: " + df.format(d) + "%"); } }
6、配置文件
sftp: ip: 192.168.1.111 port: 22 username: root password: root uploadSleep: 1000 #上传失败隔1秒重新上传 uploadRettry: 1 #重新上传的次数 serverStorageDir: /opt/zzz #服务器路径 isFileNameGBK: true #文件名是否gbk编码
7、上传测试
String src = "D:\\home\\test.xlsx"; // 本地文件名 File file = new File(src); try (FileInputStream fis = new FileInputStream(file)) { boolean upload = sftpClientUtils.upload(fis, ele.getName()); } catch (IOException e) { e.printStackTrace(); }