转载: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包

  1. <dependency>
  2. <groupId>com.jcraft</groupId>
  3. <artifactId>jsch</artifactId>
  4. <version>0.1.42</version>
  5. </dependency>

Sftp协议工具类-v0.1

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

v0.2-新增sftp连接池

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

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

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

v0.31

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

文件系统之-JAVA Sftp远程操作:的更多相关文章

  1. 在Eclipse中运行JAVA代码远程操作HBase的示例

    在Eclipse中运行JAVA代码远程操作HBase的示例 分类: 大数据 2014-03-04 13:47 3762人阅读 评论(2) 收藏 举报 下面是一个在Windows的Eclipse中通过J ...

  2. 客户端用java api 远程操作HDFS以及远程提交MR任务(源码和异常处理)

    两个类,一个HDFS文件操作类,一个是wordcount 词数统计类,都是从网上看来的.上代码: package mapreduce; import java.io.IOException; impo ...

  3. Java可以远程操作服务器的协议笔记

    1.SCPClient(本地复制到远程.远程复制到本地.目前未看到可以远程操作文件) 2.SMB协议(可以远程操作文件:新增.修改) 3.SFTPv3Client(可以远程操作文件:新增.修改)

  4. java使用Jsch实现远程操作linux服务器进行文件上传、下载,删除和显示目录信息

    1.java使用Jsch实现远程操作linux服务器进行文件上传.下载,删除和显示目录信息. 参考链接:https://www.cnblogs.com/longyg/archive/2012/06/2 ...

  5. Java网页数据采集器[续篇-远程操作]【转载】

    本期概述 上期我们学习了html页面采集后的数据查询, 但这仅仅是在本地查询数据库,如果我们想通过远程操作来进行数据的采集,存储和查询,那又该怎么做呢? 今天我们一起来学习下:如何通过本地客户端远程访 ...

  6. loadrunner 脚本开发-调用java jar文件远程操作Oracle数据库测试

    调用java jar文件远程操作Oracle数据库测试 by:授客 QQ:1033553122 测试环境 数据库:linux 下Oracle_11g_R2 Loadrunner:11 备注:想学ora ...

  7. Java SFTP 上传、下载等操作

    Java SFTP 上传.下载等操作 实际开发中用到了 SFTP 用于交换批量数据文件,然后琢磨了下这方面的东西,基于 JSch 写了个工具类记录下,便于日后使用. JSch是 SSH2 的纯Java ...

  8. Linux SSH 远程操作与传送文件

    操作系统:centos 6.5 x64 一.远程连接:在进行linux 的 ssh远程操作前,一定要确认linux 是否安装了 openssh-clients,为了方便起见,一般用yum安装即可:# ...

  9. Hadoop JAVA HDFS客户端操作

    JAVA HDFS客户端操作 通过API操作HDFS org.apache.logging.log4jlog4j-core2.8.2org.apache.hadoophadoop-common${ha ...

随机推荐

  1. DataContext.ExecuteQuery的两种方法调用

    ExecuteQuery主要用于DataContext类直接执行SQL语句的查询,在MSDN上有两种执行方法,下面为两种方法的不同调用: 1.ExecuteQuery<TResult>(S ...

  2. 使用Jquery与vuejs操作dom比较

    jquery实现添加功能 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> ...

  3. Selenium WebDriver- 操作JavaScript的confirm弹窗

    #encoding=utf-8 import unittest import time from selenium import webdriver from selenium.webdriver i ...

  4. day01_02.php的开发环境准备

    PHP开发环境的准备 此套课程推荐xampp,也就是Apache+Mysql+PHP 但是我自己的机器装的是wamp环境,稍微有一些不一样,但是不影响使用

  5. CRM知识点汇总(未完💩💩💩💩💩)

    一:项目中每个类的作用 StarkSite 对照admin中的AdminSite,相当于一个容器,用来存放类与类之间的关系. 先实例化对象,然后执行该对象的register方法.将注册类添加到_reg ...

  6. 2章 perl标量变量

    标量变量 单单存储一个值得变量   ,单个标量值 $name   为变量  区分大小写 $barney=$barney*2   第一次  取值  等号右边    :第二次  赋值 等号左边 双目操作符 ...

  7. 编译TensorFlow CPU指令集优化版

    编译TensorFlow CPU指令集优化版 如题,CPU指令集优化版,说的是针对某种特定的CPU型号进行过优化的版本.通常官方给的版本是没有针对特定CPU进行过优化的,有网友称,优化过的版本相比优化 ...

  8. iOS学习笔记44-Swift(四)枚举和结构体

    一.Swift的枚举 枚举是一系相关联的值定义的一个公共的组类型,同时能够让你在编程的时候在类型安全的情况下去使用这些值.Swift中的枚举比OC中的枚举强大得多, 因为Swift中的枚举是一等类型, ...

  9. docker 容器详解

    Docker 是一个开源的应用容器引擎,基于Go语言 并遵Apache2.0协议开源,也是一种虚拟化技术.让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后发布到任何流行的 Linux ...

  10. [TJOI2017] 城市 (树的直径,贪心)

    题目链接 Solution 这道题,调了我一晚上... 一直80分 >_<|| ... 考虑到几点: 分开任意一条边 \(u\) ,那么其肯定会断成两棵树. 肯定是分开直径上的边最优,否则 ...