文件系统之-JAVA Sftp远程操作:

Posted 梦想空间

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了文件系统之-JAVA Sftp远程操作:相关的知识,希望对你有一定的参考价值。

转载:http://blog.csdn.net/lee272616/article/details/52789018

java远程操作文件服务器(linux),使用sftp协议
版本会持续更新,
当前版本:0.31
版本更新时间:2016-10-13
版本修正说明:
1.修正连接关闭,将关闭的方法改成私有,不允许使用者自行关闭(否则会导致连接池获取错误)

2.优化删除文件及文件夹,先判断文件或文件夹是否存在,然后再删除

前言:

sftp是Secure File Transfer Protocol的缩写,安全文件传送协议。可以为传输文件提供一种安全的加密方法。sftp 与 ftp 有着几乎一样的语法和功能。SFTP 为 SSH的一部分,是一种传输档案至 Blogger 伺服器的安全方式。其实在SSH软件包中,已经包含了一个叫作SFTP(Secure File Transfer Protocol)的安全文件传输子系统,SFTP本身没有单独的守护进程,它必须使用sshd守护进程(端口号默认是22)来完成相应的连接操作,所以从某种意义上来说,SFTP并不像一个服务器程序,而更像是一个客户端程序。SFTP同样是使用加密传输认证信息和传输的数据,所以,使用SFTP是非常安全的。但是,由于这种传输方式使用了加密/解密技术,所以传输效率比普通的FTP要低得多,如果您对网络安全性要求更高时,可以使用SFTP代替FTP。

本工具基于对JSch - Java Secure Channel进行的封装,linux服务器不用安装任何插件和软件

 

使用指南:

首先是jar包

 

[html] view plain copy
 
  1. <dependency>  
  2.   <groupId>com.jcraft</groupId>  
  3.   <artifactId>jsch</artifactId>  
  4.   <version>0.1.42</version>  
  5. </dependency>  

 

Sftp协议工具类-v0.1

 

[java] view plain copy
 
  1. package com.noryar.filesystem.utils;  
  2.   
  3. import java.io.ByteArrayOutputStream;  
  4. import java.io.File;  
  5. import java.io.FileOutputStream;  
  6. import java.util.ArrayList;  
  7. import java.util.List;  
  8. import java.util.Properties;  
  9. import java.util.Vector;  
  10.   
  11. import org.apache.commons.lang.StringUtils;  
  12.   
  13. import com.jcraft.jsch.Channel;  
  14. import com.jcraft.jsch.ChannelSftp;  
  15. import com.jcraft.jsch.JSch;  
  16. import com.jcraft.jsch.JSchException;  
  17. import com.jcraft.jsch.Session;  
  18. import com.jcraft.jsch.SftpException;  
  19.   
  20. /** 
  21.  * 文件工具类. 
  22.  * @author Leon Lee 
  23.  */  
  24. public class SftpUtil {  
  25.   
  26.     /** 
  27.      * 文件路径前缀. /ddit-remote 
  28.      */  
  29.     private static final String PRE_FIX = "/test-noryar";  
  30.   
  31.     /** 
  32.      * 获取sftp协议连接. 
  33.      * @param host 主机名 
  34.      * @param port 端口 
  35.      * @param username 用户名 
  36.      * @param password 密码 
  37.      * @return 连接对象 
  38.      * @throws JSchException 异常 
  39.      */  
  40.     public static ChannelSftp getSftpConnect(final String host, final int port, final String username,  
  41.             final String password) throws JSchException {  
  42.         ChannelSftp sftp = null;  
  43.         JSch jsch = new JSch();  
  44.         jsch.getSession(username, host, port);  
  45.         Session sshSession = jsch.getSession(username, host, port);  
  46.         sshSession.setPassword(password);  
  47.         Properties sshConfig = new Properties();  
  48.         sshConfig.put("StrictHostKeyChecking", "no");  
  49.         sshSession.setConfig(sshConfig);  
  50.         sshSession.connect();  
  51.         Channel channel = sshSession.openChannel("sftp");  
  52.         channel.connect();  
  53.         sftp = (ChannelSftp) channel;  
  54.         return sftp;  
  55.     }  
  56.   
  57.     /** 
  58.      * 下载文件-sftp协议. 
  59.      * @param downloadFile 下载的文件 
  60.      * @param saveFile 存在本地的路径 
  61.      * @param sftp sftp连接 
  62.      * @return 文件 
  63.      * @throws Exception 异常 
  64.      */  
  65.     public static File download(final String downloadFile, final String saveFile, final ChannelSftp sftp)  
  66.             throws Exception {  
  67.         FileOutputStream os = null;  
  68.         File file = new File(saveFile);  
  69.         try {  
  70.             if (!file.exists()) {  
  71.                 File parentFile = file.getParentFile();  
  72.                 if (!parentFile.exists()) {  
  73.                     parentFile.mkdirs();  
  74.                 }  
  75.                 file.createNewFile();  
  76.             }  
  77.             os = new FileOutputStream(file);  
  78.             List<String> list = formatPath(downloadFile);  
  79.             sftp.get(list.get(0) + list.get(1), os);  
  80.         } catch (Exception e) {  
  81.             exit(sftp);  
  82.             throw e;  
  83.         } finally {  
  84.             os.close();  
  85.         }  
  86.         return file;  
  87.     }  
  88.   
  89.     /** 
  90.      * 下载文件-sftp协议. 
  91.      * @param downloadFile 下载的文件 
  92.      * @param saveFile 存在本地的路径 
  93.      * @param sftp sftp连接 
  94.      * @return 文件 byte[] 
  95.      * @throws Exception 异常 
  96.      */  
  97.     public static byte[] downloadAsByte(final String downloadFile, final ChannelSftp sftp) throws Exception {  
  98.         ByteArrayOutputStream os = new ByteArrayOutputStream();  
  99.         try {  
  100.             List<String> list = formatPath(downloadFile);  
  101.             sftp.get(list.get(0) + list.get(1), os);  
  102.         } catch (Exception e) {  
  103.             exit(sftp);  
  104.             throw e;  
  105.         } finally {  
  106.             os.close();  
  107.         }  
  108.         return os.toByteArray();  
  109.     }  
  110.   
  111.     /** 
  112.      * 删除文件-sftp协议. 
  113.      * @param deleteFile 要删除的文件 
  114.      * @param sftp sftp连接 
  115.      * @throws Exception 异常 
  116.      */  
  117.     public static void rmFile(final String deleteFile, final ChannelSftp sftp) throws Exception {  
  118.         try {  
  119.             sftp.rm(deleteFile);  
  120.         } catch (Exception e) {  
  121.             exit(sftp);  
  122.             throw e;  
  123.         }  
  124.     }  
  125.   
  126.     /** 
  127.      * 删除文件夹-sftp协议. 
  128.      * @param deleteFile 文件夹路径 
  129.      * @param sftp sftp连接 
  130.      * @throws Exception 异常 
  131.      */  
  132.     public static void rmDir(final String pathString, final ChannelSftp sftp) throws Exception {  
  133.         try {  
  134.             sftp.rmdir(pathString);  
  135.         } catch (Exception e) {  
  136.             exit(sftp);  
  137.             throw e;  
  138.         }  
  139.     }  
  140.   
  141.     /** 
  142.      * 上传文件-sftp协议. 
  143.      * @param srcFile 源文件 
  144.      * @param dir 保存路径 
  145.      * @param fileName 保存文件名 
  146.      * @param sftp sftp连接 
  147.      * @throws Exception 异常 
  148.      */  
  149.     private static void uploadFile(final String srcFile, final String dir, final String fileName, final ChannelSftp sftp)  
  150.             throws Exception {  
  151.         mkdir(dir, sftp);  
  152.         sftp.cd(dir);  
  153.         sftp.put(srcFile, fileName);  
  154.     }  
  155.   
  156.     /** 
  157.      * 上传文件-sftp协议. 
  158.      * @param srcFile 源文件路径,/xxx/xxx.zip 或 x:/xxx/xxx.zip; 
  159.      * @param sftp sftp连接 
  160.      * @throws Exception 异常 
  161.      */  
  162.     public static void uploadFile(final String srcFile, final ChannelSftp sftp) throws Exception {  
  163.         try {  
  164.             File file = new File(srcFile);  
  165.             if (file.exists()) {  
  166.                 List<String> list = formatPath(srcFile);  
  167.                 uploadFile(srcFile, list.get(0), list.get(1), sftp);  
  168.             }  
  169.         } catch (Exception e) {  
  170.             exit(sftp);  
  171.             throw e;  
  172.         }  
  173.     }  
  174.   
  175.     /** 
  176.      * 根据路径创建文件夹. 
  177.      * @param dir 路径 必须是 /xxx/xxx/xxx/ 不能就单独一个/ 
  178.      * @param sftp sftp连接 
  179.      * @throws Exception 异常 
  180.      */  
  181.     public static boolean mkdir(final String dir, final ChannelSftp sftp) throws Exception {  
  182.         try {  
  183.             if (StringUtils.isBlank(dir))  
  184.                 return false;  
  185.             String md = dir.replaceAll("\\\\", "/");  
  186.             if (md.indexOf("/") != 0 || md.length() == 1)  
  187.                 return false;  
  188.             return mkdirs(md, sftp);  
  189.         } catch (Exception e) {  
  190.             exit(sftp);  
  191.             throw e;  
  192.         }  
  193.     }  
  194.   
  195.     /** 
  196.      * 递归创建文件夹. 
  197.      * @param dir 路径 
  198.      * @param sftp sftp连接 
  199.      * @return 是否创建成功 
  200.      * @throws SftpException 异常 
  201.      */  
  202.     private static boolean mkdirs(final String dir, final ChannelSftp sftp) throws SftpException {  
  203.         String dirs = dir.substring(1, dir.length() - 1);  
  204.         String[] dirArr = dirs.split("/");  
  205.         String base = "";  
  206.         for (String d : dirArr) {  
  207.             base += "/" + d;  
  208.             if (dirExist(base + "/", sftp)) {  
  209.                 continue;  
  210.             } else {  
  211.                 sftp.mkdir(base + "/");  
  212.             }  
  213.         }  
  214.         return true;  
  215.     }  
  216.   
  217.     /** 
  218.      * 判断文件夹是否存在. 
  219.      * @param dir 文件夹路径, /xxx/xxx/ 
  220.      * @param sftp sftp协议 
  221.      * @return 是否存在 
  222.      */  
  223.     public static boolean dirExist(final String dir, final ChannelSftp sftp) {  
  224.         try {  
  225.             Vector<?> vector = sftp.ls(dir);  
  226.             if (null == vector)  
  227.                 return false;  
  228.             else  
  229.                 return true;  
  230.         } catch (SftpException e) {  
  231.             return false;  
  232.         }  
  233.     }  
  234.   
  235.     /** 
  236.      * 格式化路径. 
  237.      * @param srcPath 原路径. /xxx/xxx/xxx.yyy 或 X:/xxx/xxx/xxx.yy 
  238.      * @return list, 第一个是路径(/xxx/xxx/),第二个是文件名(xxx.yy) 
  239.      */  
  240.     public static List<String> formatPath(final String srcPath) {  
  241.         List<String> list = new ArrayList<String>(2);  
  242.         String dir = "";  
  243.         String fileName = "";  
  244.         String repSrc = srcPath.replaceAll("\\\\", "/");  
  245.         int firstP = repSrc.indexOf("/");  
  246.         int lastP = repSrc.lastIndexOf("/");  
  247.         fileName = repSrc.substring(lastP + 1);  
  248.         dir = repSrc.substring(firstP, lastP);  
  249.         dir = PRE_FIX + (dir.length() == 1 ? dir : (dir + "/"));  
  250.         list.add(dir);  
  251.         list.add(fileName);  
  252.         return list;  
  253.     }  
  254.   
  255.     /** 
  256.      * 关闭协议-sftp协议. 
  257.      * @param sftp sftp连接 
  258.      */  
  259.     public static void exit(final ChannelSftp sftp) {  
  260.         sftp.exit();  
  261.     }  
  262.   
  263.     public static void main(String[] args) throws Exception {  
  264.         ChannelSftp sftp = getSftpConnect("192.168.0.35", 22, "root", "root");  
  265.         String pathString = "C:\\test\\aaa\\Foxmail7.zip";  
  266.         File file = new File(pathString);  
  267.         System.out.println("上传文件开始...");  
  268.         uploadFile(pathString, sftp);  
  269.         System.out.println("上传成功,开始删除本地文件...");  
  270.         file.delete();  
  271.         System.out.println("删除完成,开始校验本地文件...");  
  272.         if (!file.exists()) {  
  273.             System.out.println("文件不存在,开始从远程服务器获取...");  
  274.             download(pathString, pathString, sftp);  
  275.             System.out.println("下载完成");  
  276.         } else {  
  277.             System.out.println("在本地找到文件");  
  278.         }  
  279.         exit(sftp);  
  280.         System.exit(0);  
  281.     }  
  282. }  

v0.2-新增sftp连接池

由于创建sftp连接的花销比较大,因此考虑相同主机的连接存放在连接池中,下次获取sftp连接的时候直接去连接池获取
以下代码替换v0.1版的getSftpConnect()方法,并加上成员变量即可
[java] view plain copy
 
  1. /** 
  2.  * sftp连接池. 
  3.  */  
  4. private static final Map<String, Channel> SFTP_CHANNEL_POOL = new HashMap<String, Channel>();  
  5.   
  6. /** 
  7.  * 获取sftp协议连接. 
  8.  * @param host 主机名 
  9.  * @param port 端口 
  10.  * @param username 用户名 
  11.  * @param password 密码 
  12.  * @return 连接对象 
  13.  * @throws JSchException 异常 
  14.  */  
  15. public static ChannelSftp getSftpConnect(final String host, final int port, final String username,  
  16.         final String password) throws JSchException {  
  17.     Session sshSession = null;  
  18.     Channel channel = null;  
  19.     ChannelSftp sftp = null;  
  20.     String key = host + "," + port + "," + username + "," + password;  
  21.     if (null == SFTP_CHANNEL_POOL.get(key)) {  
  22.         JSch jsch = new JSch();  
  23.         jsch.getSession(username, host, port);  
  24.         sshSession = jsch.getSession(username, host, port);  
  25.         sshSession.setPassword(password);  
  26.         Properties sshConfig = new Properties();  
  27.         sshConfig.put("StrictHostKeyChecking", "no");  
  28.         sshSession.setConfig(sshConfig);  
  29.         sshSession.connect();  
  30.         channel = sshSession.openChannel("sftp");  
  31.         channel.connect();  
  32.         SFTP_CHANNEL_POOL.put(key, channel);  
  33.     } else {  
  34.         channel = SFTP_CHANNEL_POOL.get(key);  
  35.         sshSession = channel.getSession();  
  36.         if (!sshSession.isConnected())  
  37.             sshSession.connect();  
  38.         if (!channel.isConnected())  
  39.             channel.connect();  
  40.     }  
  41.     sftp = (ChannelSftp) channel;  
  42.     return sftp;  
  43. }  

v0.3-修改了一些bug,新增递归删除文件夹功能

[java] view plain copy
 
  1. package com.noryar.filesystem.utils;  
  2.   
  3. import java.io.ByteArrayOutputStream;  
  4. import java.io.File;  
  5. import java.io.FileOutputStream;  
  6. import java.util.ArrayList;  
  7. import java.util.HashMap;  
  8. import java.util.List;  
  9. import java.util.Map;  
  10. import java.util.Properties;  
  11. import java.util.Vector;  
  12.   
  13. import org.apache.commons.lang.StringUtils;  
  14.   
  15. import com.jcraft.jsch.Channel;  
  16. import com.jcraft.jsch.ChannelSftp;  
  17. import com.jcraft.jsch.ChannelSftp.LsEntry;  
  18. import com.jcraft.jsch.JSch;  
  19. import com.jcraft.jsch.JSchException;  
  20. import com.jcraft.jsch.Session;  
  21. import com.jcraft.jsch.SftpException;  
  22.   
  23. /** 
  24.  * 文件工具类.<br> 
  25.  * 1.所有的文件路径必须以‘/‘开头和结尾,否则路径最后一部分会被当做是文件名<br> 
  26.  * 2.方法出现异常的时候,会关闭sftp连接(但是不会关闭session和channel),异常会抛出 
  27.  * @author Leon Lee 
  28.  */  
  29. public class SftpUtil {  
  30.   
  31.     /** 
  32.      * 文件路径前缀. /ddit-remote 
  33.      */  
  34.     private static final String PRE_FIX = "/test-noryar";  
  35.   
  36.     /** 
  37.      * sftp连接池. 
  38.      */  
  39.     private static final Map<String, Channel> SFTP_CHANNEL_POOL = new HashMap<String, Channel>();  
  40.   
  41.     /** 
  42.      * 获取sftp协议连接. 
  43.      * @param host 主机名 
  44.      * @param port 端口 
  45.      * @param username 用户名 
  46.      * @param password 密码 
  47.      * @return 连接对象 
  48.      * @throws JSchException 异常 
  49.      */  
  50.     public static ChannelSftp getSftpConnect(final String host, final int port, final String username,  
  51.             final String password) throws JSchException {  
  52.         Session sshSession = null;  
  53.         Channel channel = null;  
  54.         ChannelSftp sftp = null;  
  55.         String key = host + "," + port + "," + username + "," + password;  
  56.         if (null == SFTP_CHANNEL_POOL.get(key)) {  
  57.             JSch jsch = new JSch();  
  58.             jsch.getSession(username, host, port);  
  59.             sshSession = jsch.getSession(username, host, port);  
  60.             sshSession.setPassword(password);  
  61.             Properties sshConfig = new Properties();  
  62.             sshConfig.put("StrictHostKeyChecking", "no");  
  63.             sshSession.setConfig(sshConfig);  
  64.             sshSession.connect();  
  65.             channel = sshSession.openChannel("sftp");  
  66.             channel.connect();  
  67.             SFTP_CHANNEL_POOL.put(key, channel);  
  68.         } else {  
  69.             channel = SFTP_CHANNEL_POOL.get(key);  
  70.             sshSession = channel.getSession();  
  71.             if (!sshSession.isConnected())  
  72.                 sshSession.connect();  
  73.             if (!channel.isConnected())  
  74.                 channel.connect();  
  75.         }  
  76.         sftp = (ChannelSftp) channel;  
  77.         return sftp;  
  78.     }  
  79.   
  80.     /** 
  81.      * 下载文件-sftp协议. 
  82.      * @param downloadFile 下载的文件 
  83.      * @param saveFile 存在本地的路径 
  84.      * @param sftp sftp连接 
  85.      * @return 文件 
  86.      * @throws Exception 异常 
  87.      */  
  88.     public static File download(final String downloadFile, final String saveFile, final ChannelSftp sftp)  
  89.             throws Exception {  
  90.         FileOutputStream os = null;  
  91.         File file = new File(saveFile);  
  92.         try {  
  93.             if (!file.exists()) {  
  94.                 File parentFile = file.getParentFile();  
  95.                 if (!parentFile.exists()) {  
  96.                     parentFile.mkdirs();  
  97.                 }  
  98.                 file.createNewFile();  
  99.             }  
  100.             os = new FileOutputStream(file);  
  101.             List<String> list = formatPath(downloadFile);  
  102.             sftp.get(list.get(0) + list.get(1), os);  
  103.         } catch (Exception e) {  
  104.             exit(sftp);  
  105.             e.getMessage();  
  106.             throw e;  
  107.         } finally {  
  108.             os.close();  
  109.         }  
  110.         return file;  
  111.     }  
  112.   
  113.     /** 
  114.      * 下载文件-sftp协议. 
  115.      * @param downloadFile 下载的文件 
  116.      * @param saveFile 存在本地的路径 
  117.      * @param sftp sftp连接 
  118.      * @return 文件 byte[] 
  119.      * @throws Exception 异常 
  120.      */  
  121.     public static byte[] downloadAsByte(final String downloadFile, final ChannelSftp sftp) throws Exception {  
  122.         ByteArrayOutputStream os = new ByteArrayOutputStream();  
  123.         try {  
  124.             List<String> list = formatPath(downloadFile);  
  125.             sftp.get(list.get(0) + list.get(1), os);  
  126.         } catch (Exception e) {  
  127.             exit(sftp);  
  128.             throw e;  
  129.         } finally {  
  130.             os.close();  
  131.         }  
  132.         return os.toByteArray();  
  133.     }  
  134.   
  135.     /** 
  136.      * 删除文件-sftp协议. 
  137.      * @param pathString 要删除的文件 
  138.      * @param sftp sftp连接 
  139.      * @throws Exception 异常 
  140.      */  
  141.     public static void rmFile(final String pathString, final ChannelSftp sftp) throws Exception {  
  142.         try {  
  143.             List<String> list = formatPath(pathString);  
  144.             sftp.rm(list.get(0) + list.get(1));  
  145.         } catch (Exception e) {  
  146.             exit(sftp);  
  147.             throw e;  
  148.         }  
  149.     }  
  150.   
  151.     /** 
  152.      * 删除文件夹-sftp协议.如果文件夹有内容,则会抛出异常. 
  153.      * @param pathString 文件夹路径 
  154.      * @param sftp sftp连接 
  155.      * @param resursion 递归删除 
  156.      * @throws Exception 异常 
  157.      */  
  158.     public static void rmDir(final String pathString, final ChannelSftp sftp, final boolean recursion) throws Exception {  
  159.         try {  
  160.             String fp = formatPath(pathString).get(0);  
  161.             if (recursion)  
  162.                 exeRmRec(fp, sftp);  
  163.             else  
  164.                 sftp.rmdir(fp);  
  165.         } catch (Exception e) {  
  166.             exit(sftp);  
  167.             throw e;  
  168.         }  
  169.     }  
  170.   
  171.     /** 
  172.      * 递归删除执行. 
  173.      * @param pathString 文件路径 
  174.      * @param sftp sftp连接 
  175.      * @throws SftpException 
  176.      */  
  177.     private static void exeRmRec(final String pathString, final ChannelSftp sftp) throws SftpException {  
  178.         @SuppressWarnings("unchecked")  
  179.         Vector<LsEntry> vector = sftp.ls(pathString);  
  180.         if (vector.size() == 1) { // 文件,直接删除  
  181.             sftp.rm(pathString);  
  182.         } else if (vector.size() == 2) { // 空文件夹,直接删除  
  183.             sftp.rmdir(pathString);  
  184.         } else {  
  185.             String fileName = "";  
  186.             // 删除文件夹下所有文件  
  187.             for (LsEntry en : vector) {  
  188.                 fileName = en.getFilename();  
  189.                 if (".".equals(fileName) || "..".equals(fileName)) {  
  190.                     continue;  
  191.                 } else {  
  192.                     exeRmRec(pathString + "/" + fileName, sftp);  
  193.                 }  
  194.             }  
  195.             // 删除文件夹  
  196.             sftp.rmdir(pathString);  
  197.         }  
  198.     }  
  199.   
  200.     /** 
  201.      * 上传文件-sftp协议. 
  202.      * @param srcFile 源文件 
  203.      * @param dir 保存路径 
  204.      * @param fileName 保存文件名 
  205.      * @param sftp sftp连接 
  206.      * @throws Exception 异常 
  207.      */  
  208.     private static void uploadFile(final String srcFile, final String dir, final String fileName, final ChannelSftp sftp)  
  209.             throws Exception {  
  210.         mkdir(dir, sftp);  
  211.         sftp.cd(dir);  
  212.         sftp.put(srcFile, fileName);  
  213.     }  
  214.   
  215.     /** 
  216.      * 上传文件-sftp协议. 
  217.      * @param srcFile 源文件路径,/xxx/xx.yy 或 x:/xxx/xxx.yy 
  218.      * @param sftp sftp连接 
  219.      * @return 上传成功与否 
  220.      * @throws Exception 异常 
  221.      */  
  222.     public static boolean uploadFile(final String srcFile, final ChannelSftp sftp) throws Exception {  
  223.         try {  
  224.             File file = new File(srcFile);  
  225.             if (file.exists()) {  
  226.                 List<String> list = formatPath(srcFile);  
  227.                 uploadFile(srcFile, list.get(0), list.get(1), sftp);  
  228.                 return true;  
  229.             }  
  230.             return false;  
  231.         } catch (Exception e) {  
  232.             exit(sftp);  
  233.             throw e;  
  234.         }  
  235.     }  
  236.   
  237.     /** 
  238.      * 根据路径创建文件夹. 
  239.      * @param dir 路径 必须是 /xxx/xxx/ 不能就单独一个/ 
  240.      * @param sftp sftp连接 
  241.      * @throws Exception 异常 
  242.      */  
  243.     public static boolean mkdir(final String dir, final ChannelSftp sftp) throws Exception {  
  244.         try {  
  245.             if (StringUtils.isBlank(dir))  
  246.                 return false;  
  247.             String md = dir.replaceAll("\\\\", "/");  
  248.             if (md.indexOf("/") != 0 || md.length() == 1)  
  249.                 return false;  
  250.             return mkdirs(md, sftp);  
  251.         } catch (Exception e) {  
  252.             exit(sftp);  
  253.             throw e;  
  254.         }  
  255.     }  
  256.   
  257.     /** 
  258.      * 递归创建文件夹. 
  259.      * @param dir 路径 
  260.      * @param sftp sftp连接 
  261.      * @return 是否创建成功 
  262.      * @throws SftpException 异常 
  263.      */  
  264.     private static boolean mkdirs(final String dir, final ChannelSftp sftp) throws SftpException {  
  265.         String dirs = dir.substring(1, dir.length() - 1);  
  266.         String[] dirArr = dirs.split("/");  
  267.         String base = "";  
  268.         for (String d : dirArr) {  
  269.             base += "/" + d;  
  270.             if (dirExist(base + "/", sftp)) {  
  271.                 continue;  
  272.             } else {  
  273.                 sftp.mkdir(base + "/");  
  274.             }  
  275.         }  
  276.         return true;  
  277.     }  
  278.   
  279.     /** 
  280.      * 判断文件夹是否存在. 
  281.      * @param dir 文件夹路径, /xxx/xxx/ 
  282.      * @param sftp sftp协议 
  283.      * @return 是否存在 
  284.      */  
  285.     private static boolean dirExist(final String dir, final ChannelSftp sftp) {  
  286.         try {  
  287.             Vector<?> vector = sftp.ls(dir);  
  288.             if (null == vector)  
  289.                 return false;  
  290.             else  
  291.                 return true;  
  292.         } catch (SftpException e) {  
  293.             return false;  
  294.         }  
  295.     }  
  296.   
  297.     /** 
  298.      * 格式化路径. 
  299.      * @param srcPath 原路径. /xxx/xxx/xxx.yyy 或 X:/xxx/xxx/xxx.yy 
  300.      * @return list, 第一个是路径(/xxx/xxx/),第二个是文件名(xxx.yy) 
  301.      */  
  302.     public static List<String> formatPath(final String srcPath) {  
  303.         List<String> list = new ArrayList<String>(2);  
  304.         String repSrc = srcPath.replaceAll("\\\\", "/");  
  305.         int firstP = repSrc.indexOf("/");  
  306.         int lastP = repSrc.lastIndexOf("/");  
  307.         String fileName = lastP + 1 == repSrc.length() ? "" : repSrc.substring(lastP + 1);  
  308.         String dir = firstP == -1 ? "" : repSrc.substring(firstP, lastP);  
  309.         dir = PRE_FIX + (dir.length() == 1 ? dir : (dir + "/"));  
  310.         list.add(dir);  
  311.         list.add(fileName);  
  312.         return list;  
  313.     }  
  314.   
  315.     /** 
  316.      * 关闭协议-sftp协议. 
  317.      * @param sftp sftp连接 
  318.      */  
  319.     public static void exit(final ChannelSftp sftp) {  
  320.         sftp.exit();  
  321.     }  
  322.   
  323.     public static void main(String[] args) throws Exception {  
  324.         ChannelSftp sftp = getSftpConnect("192.168.0.35", 22, "root", "root");  
  325.         // String pathString = "C:\\test\\ccc\\Foxmail7.zip";  
  326.         // File file = new File(pathString);  
  327.         // System.out.println("上传文件开始...");  
  328.         // uploadFile(pathString, sftp);  
  329.         // System.out.println("上传成功,开始删除本地文件...");  
  330.         // file.delete();  
  331.         // System.out.println("删除完成,开始校验本地文件...");  
  332.         // if (!file.exists()) {  
  333.         // System.out.println("文件不存在,开始从远程服务器获取...");  
  334.         // download(pathString, pathString, sftp);  
  335.         // System.out.println("下载完成");  
  336.         // } else {  
  337.         // System.out.println("在本地找到文件");  
  338.         // }  
  339.         rmDir("", sftp, true);  
  340.         exit(sftp);  
  341.         System.exit(0);  
  342.     }  
  343. }  

v0.31

修正连接关闭,将关闭的方法改成私有,不允许使用者自行关闭(否则会导致连接池获取错误)
优化删除文件及文件夹,先判断文件或文件夹是否存在,然后再删除
[java] view plain copy
 
  1. package com.noryar.filesystem.utils;  
  2.   
  3. import java.io.ByteArrayOutputStream;  
  4. import java.io.File;  
  5. import java.io.FileOutputStream;  
  6. import java.util.ArrayList;  
  7. import java.util.HashMap;  
  8. import java.util.List;  
  9. import java.util.Map;  
  10. import java.util.Properties;  
  11. import java.util.Vector;  
  12.   
  13. import org.apache.commons.lang.StringUtils;  
  14.   
  15. import com.jcraft.jsch.Channel;  
  16. import com.jcraft.jsch.ChannelSftp;  
  17. import com.jcraft.jsch.ChannelSftp.LsEntry;  
  18. import com.jcraft.jsch.JSch;  
  19. import com.jcraft.jsch.JSchException;  
  20. import com.jcraft.jsch.Session;  
  21. import com.jcraft.jsch.SftpException;  
  22.   
  23. /** 
  24.  * 文件工具类.<br> 
  25.  * 1.所有的文件路径必须以‘/‘开头和结尾,否则路径最后一部分会被当做是文件名<br> 
  26.  * 2. @since version-0.3 方法出现异常的时候,<del>会关闭sftp连接(但是不会关闭session和channel)</del>(del @ version 0.31),异常会抛出<br> 
  27.  * @author Leon Lee 
  28.  */  
  29. public class SftpUtil {  
  30.   
  31.     /** 
  32.      * 文件路径前缀. /ddit-remote 
  33.      */  
  34.     private static final String PRE_FIX = "/test-noryar";  
  35.   
  36.     /** 
  37.      * sftp连接池. 
  38.      */  
  39.     private static final Map<String, Channel> SFTP_CHANNEL_POOL = new HashMap<String, Channel>();  
  40.   
  41.     /** 
  42.      * 获取sftp协议连接. 
  43.      * @param host 主机名 
  44.      * @param port 端口 
  45.      * @param username 用户名 
  46.      * @param password 密码 
  47.      * @return 连接对象 
  48.      * @throws JSchException 异常 
  49.      */  
  50.     public static ChannelSftp getSftpConnect(final String host, final int port, final String username,  
  51.             final String password) throws JSchException {  
  52.         Session sshSession = null;  
  53.         Channel channel = null;  
  54.         ChannelSftp sftp = null;  
  55.         String key = host + "," + port + "," + username + "," + password;  
  56.         if (null == SFTP_CHANNEL_POOL.get(key)) {  
  57.             JSch jsch = new JSch();  
  58.             jsch.getSession(username, host, port);  
  59.             sshSession = jsch.getSession(username, host, port);  
  60.             sshSession.setPassword(password);  
  61.             Properties sshConfig = new Properties();  
  62.             sshConfig.put("StrictHostKeyChecking", "no");  
  63.             sshSession.setConfig(sshConfig);  
  64.             sshSession.connect();  
  65.             channel = sshSession.openChannel("sftp");  
  66.             channel.connect();  
  67.             SFTP_CHANNEL_POOL.put(key, channel);  
  68.         } else {  
  69.             channel = SFTP_CHANNEL_POOL.get(key);  
  70.             sshSession = channel.getSession();  
  71.             if (!sshSession.isConnected())  
  72.                 sshSession.connect();  
  73.             if (!channel.isConnected())  
  74.                 channel.connect();  
  75.         }  
  76.         sftp = (ChannelSftp) channel;  
  77.         return sftp;  
  78.     }  
  79.   
  80.     /** 
  81.      * 下载文件-sftp协议. 
  82.      * @param downloadFile 下载的文件 
  83.      * @param saveFile 存在本地的路径 
  84.      * @param sftp sftp连接 
  85.      * @return 文件 
  86.      * @throws Exception 异常 
  87.      */  
  88.     public static File download(final String downloadFile, final String saveFile, final ChannelSftp sftp)  
  89.             throws Exception {  
  90.         FileOutputStream os = null;  
  91.         File file = new File(saveFile);  
  92.         try {  
  93.             if (!file.exists()) {  
  94.                 File parentFile = file.getParentFile();  
  95.                 if (!parentFile.exists()) {  
  96.                     parentFile.mkdirs();  
  97.                 }  
  98.                 file.createNewFile();  
  99.             }  
  100.             os = new FileOutputStream(file);  
  101.             List<String> list = formatPath(downloadFile);  
  102.             sftp.get(list.get(0) + list.get(1), os);  
  103.         } catch (Exception e) {  
  104.             throw e;  
  105.         } finally {  
  106.             os.close();  
  107.         }  
  108.         return file;  
  109.     }  
  110.   
  111.     /** 
  112.      * 下载文件-sftp协议. 
  113.      * @param downloadFile 下载的文件 
  114.      * @param saveFile 存在本地的路径 
  115.      * @param sftp sftp连接 
  116.      * @return 文件 byte[] 
  117.      * @throws Exception 异常 
  118.      */  
  119.     public static byte[] downloadAsByte(final String downloadFile, final ChannelSftp sftp) throws Exception {  
  120.         ByteArrayOutputStream os = new ByteArrayOutputStream();  
  121.         try {  
  122.             List<String> list = formatPath(downloadFile);  
  123.             sftp.get(list.get(0) + list.get(1), os);  
  124.         } catch (Exception e) {  
  125.             throw e;  
  126.         } finally {  
  127.             os.close();  
  128.         }  
  129.         return os.toByteArray();  
  130.     }  
  131.   
  132.     /** 
  133.      * 删除文件-sftp协议. 
  134.      * @param pathString 要删除的文件 
  135.      * @param sftp sftp连接 
  136.      * @throws SftpException 异常 
  137.      */  
  138.     public static void rmFile(final String pathString, final ChannelSftp sftp) throws SftpException {  
  139.         List<String> list = formatPath(pathString);  
  140.         String dir = list.get(0);  
  141.         String file = list.get(1);  
  142.         if (dirExist(dir + file, sftp)) {  
  143.             sftp.rm(list.get(0) + list.get(1));  
  144.         }  
  145.     }  
  146.   
  147.     /** 
  148.      * 删除文件夹-sftp协议.如果文件夹有内容,则会抛出异常. 
  149.      * @param pathString 文件夹路径 
  150.      * @param sftp sftp连接 
  151.      * @param resursion 递归删除 
  152.      * @throws SftpException 异常 
  153.      */  
  154.     public static void rmDir(final String pathString, final ChannelSftp sftp, final boolean recursion)  
  155.             throws SftpException {  
  156.         String fp = formatPath(pathString).get(0);  
  157.         if (dirExist(fp, sftp)) {  
  158.             if (recursion)  
  159.                 exeRmRec(fp, sftp);  
  160.             else  
  161.                 sftp.rmdir(fp);  
  162.         }  
  163.     }  
  164.   
  165.     /** 
  166.      * 递归删除执行. 
  167.      * @param pathString 文件路径 
  168.      * @param sftp sftp连接 
  169.      * @throws SftpException 
  170.      */  
  171.     private static void exeRmRec(final String pathString, final ChannelSftp sftp) throws SftpException {  
  172.         @SuppressWarnings("unchecked")  
  173.         Vector<LsEntry> vector = sftp.ls(pathString);  
  174.         if (vector.size() == 1) { // 文件,直接删除  
  175.             sftp.rm(pathString);  
  176.         } else if (vector.size() == 2) { // 空文件夹,直接删除  
  177.             sftp.rmdir(pathString);  
  178.         } else {  
  179.             String fileName = "";  
  180.             // 删除文件夹下所有文件  
  181.             for (LsEntry en : vector) {  
  182.                 fileName = en.getFilename();  
  183.                 if (".".equals(fileName) || "..".equals(fileName)) {  
  184.                     continue;  
  185.                 } else {  
  186.                     exeRmRec(pathString + "/" + fileName, sftp);  
  187.                 }  
  188.             }  
  189.             // 删除文件夹  
  190.             sftp.rmdir(pathString);  
  191.         }  
  192.     }  
  193.   
  194.     /** 
  195.      * 上传文件-sftp协议. 
  196.      * @param srcFile 源文件 
  197.      * @param dir 保存路径 
  198.      * @param fileName 保存文件名 
  199.      * @param sftp sftp连接 
  200.      * @throws Exception 异常 
  201.      */  
  202.     private static void uploadFile(final String srcFile, final String dir, final String fileName, final ChannelSftp sftp)  
  203.             throws SftpException {  
  204.         mkdir(dir, sftp);  
  205.         sftp.cd(dir);  
  206.         sftp.put(srcFile, fileName);  
  207.     }  
  208.   
  209.     /** 
  210.      * 上传文件-sftp协议. 
  211.      * @param srcFile 源文件路径,/xxx/xx.yy 或 x:/xxx/xxx.yy 
  212.      * @param sftp sftp连接 
  213.      * @return 上传成功与否 
  214.      * @throws SftpException 异常 
  215.      */  
  216.     public static boolean uploadFile(final String srcFile, final ChannelSftp sftp) throws SftpException {  
  217.         File file = new File(srcFile);  
  218.         if (file.exists()) {  
  219.             List<String> list = formatPath(srcFile);  
  220.             uploadFile(srcFile, list.get(0), list.get(1), sftp);  
  221.             return true;  
  222.         }  
  223.         return false;  
  224.     }  
  225.   
  226.     /** 
  227.      * 根据路径创建文件夹. 
  228.      * @param dir 路径 必须是 /xxx/xxx/ 不能就单独一个/ 
  229.      * @param sftp sftp连接 
  230.      * @throws SftpException 异常 
  231.      */  
  232.     public static boolean mkdir(final String dir, final ChannelSftp sftp) throws SftpException {  
  233.         if (StringUtils.isBlank(dir))  
  234.             return false;  
  235.         String md = dir.replaceAll("\\\\", "/");  
  236.         if (md.indexOf("/") != 0 || md.length() == 1)  
  237.             return false;  
  238.         return mkdirs(md, sftp);  
  239.     }  
  240.   
  241.     /** 
  242.      * 递归创建文件夹. 
  243.      * @param dir 路径 
  244.      * @param sftp sftp连接 
  245.      * @return 是否创建成功 
  246.      * @throws SftpException 异常 
  247.      */  
  248.     private static boolean mkdirs(final String dir, final ChannelSftp sftp) throws SftpException {  
  249.         String dirs = dir.substring(1, dir.length() - 1);  
  250.         String[] dirArr = dirs.split("/");  
  251.         String base = "";  
  252.         for (String d : dirArr) {  
  253.             base += "/" + d;  
  254.             if (dirExist(base + "/", sftp)) {  
  255.                 continue;  
  256.             } else {  
  257.                 sftp.mkdir(base + "/");  
  258.             }  
  259.         }  
  260.         return true;  
  261.     }  
  262.   
  263.     /** 
  264.      * 判断文件夹是否存在. 
  265.      * @param dir 文件夹路径, /xxx/xxx/ 
  266.      * @param sftp sftp协议 
  267.      * @return 是否存在 
  268.      */  
  269.     private static boolean dirExist(final String dir, final ChannelSftp sftp) {  
  270.         try {  
  271.             Vector<?> vector = sftp.ls(dir);  
  272.             if (null == vector)  
  273.                 return false;  
  274.             else  
  275.                 return true;  
  276.         } catch (SftpException e) {  
  277.             return false;  
  278.         }  
  279.     }  
  280.   
  281.     /** 
  282.      * 格式化路径. 
  283.      * @param srcPath 原路径. /xxx/xxx/xxx.yyy 或 X:/xxx/xxx/xxx.yy 
  284.      * @return list, 第一个是路径(/xxx/xxx/),第二个是文件名(xxx.yy) 
  285.      */  
  286.     public static List<String> formatPath(final String srcPath) {  
  287.         List<String> list = new ArrayList<String>(2);  
  288.         String repSrc = srcPath.replaceAll("\\\\", "/");  
  289.         int firstP = repSrc.indexOf("/");  
  290.         int lastP = repSrc.lastIndexOf("/");  
  291.         String fileName = lastP + 1 == repSrc.length() ? "" : repSrc.substring(lastP + 1);  
  292.         String dir = firstP == -1 ? "" : repSrc.substring(firstP, lastP);  
  293.         dir = PRE_FIX + (dir.length() == 1 ? dir : (dir + "/"));  
  294.         list.add(dir);  
  295.         list.add(fileName);  
  296.         return list;  
  297.     }  
  298.   
  299.     /** 
  300.      * 关闭协议-sftp协议.(关闭会导致连接池异常,因此不建议用户自定义关闭) 
  301.      * @param sftp sftp连接 
  302.      */  
  303.     private static void exit(final ChannelSftp sftp) {  
  304.         sftp.exit();  
  305.     }  
  306.   
  307.     public static void main(String[] args) throws Exception {  
  308.         ChannelSftp sftp = getSftpConnect("192.168.0.35", 22, "root", "root");  
  309.         // String pathString = "C:\\test\\ccc\\Foxmail7.zip";  
  310.         // File file = new File(pathString);  
  311.         // System.out.println("上传文件开始...");  
  312.         // uploadFile(pathString, sftp);  
  313.         // System.out.println("上传成功,开始删除本地文件...");  
  314.         // file.delete();  
  315.         // System.out.println("删除完成,开始校验本地文件...");  
  316.         // if (!file.exists()) {  
  317.         // System.out.println("文件不存在,开始从远程服务器获取...");  
  318.         // download(pathString, pathString, sftp);  
  319.         // System.out.println("下载完成");  
  320.         // } else {  
  321.         // System.out.println("在本地找到文件");  
  322.         // }  
  323.         // rmDir("", sftp, true);  
  324.         String path = "E:\\aaa.zip";  
  325.         File file = SftpUtil.download(path, path, sftp);  
  326.         // SftpUtil.exit(sftp);  
  327.         exit(sftp);  
  328.         System.exit(0);  
  329.     }  
  330. }  







以上是关于文件系统之-JAVA Sftp远程操作:的主要内容,如果未能解决你的问题,请参考以下文章

Win10命令行实现对Linux(CentOS)的SSH远程操作SFTP传输文件

Win10命令行实现对Linux(CentOS)的SSH远程操作SFTP传输文件

转:Windows下用sftp自动下载文件

公司官网建站笔记:腾讯云服务器装CentOS8.2系统重置密码远程ssh登陆sftp传递文件以及新建开发者账户

在IDEA中配置SFTP远程Linux服务器系统

公司官网建站笔记:腾讯云服务器装CentOS8.2系统重置密码远程ssh登陆sftp传递文件以及新建开发者账户