文件系统之-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. 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()方法,并加上成员变量即可

[java] view plain copy

  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,新增递归删除文件夹功能

[java] view plain copy

  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

修正连接关闭,将关闭的方法改成私有,不允许使用者自行关闭(否则会导致连接池获取错误)

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

[java] view plain copy

  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. }
时间: 2024-10-13 11:33:56

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

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

两个类,一个HDFS文件操作类,一个是wordcount 词数统计类,都是从网上看来的.上代码: package mapreduce; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.BlockLocation; import org.apac

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

1.java使用Jsch实现远程操作linux服务器进行文件上传.下载,删除和显示目录信息. 参考链接:https://www.cnblogs.com/longyg/archive/2012/06/25/2556576.html https://www.cnblogs.com/longyg/archive/2012/06/25/2561332.html https://www.cnblogs.com/qdwyg2013/p/5650764.html#top 引入jar包的maven依赖如下所示:

hadoop2.5.2学习及实践笔记(六)—— Hadoop文件系统及其java接口

文件系统概述 org.apache.hadoop.fs.FileSystem是hadoop的抽象文件系统,为不同的数据访问提供了统一的接口,并提供了大量具体文件系统的实现,满足hadoop上各种数据访问需求,如以下几个具体实现(原表格见<hadoop权威指南>): 文件系统 URI方案 Java实现 (org.apache.hadoop) 定义 Local file fs.LocalFileSystem 支持有客户端校验和本地文件系统.带有校验和的本地系统文件在fs.RawLocalFileS

Java Web 远程调试

Java Web 远程 调试 Tomcat 下载压缩版服务器 环境:Tomcat.Eclipse,做远程调试我们并不需要其他特殊插件 1.配置Tomcat/bin/startup.bat 在前面增加代码:SET CATALINA_OPTS=-server -Xdebug -Xnoagent -Djava.compiler=NONE -   Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000 其中8000即为我们远程调试的端口,

Java字节码操作开源框架简介

avassist  Javassist是一个开源的分析.编辑和创建Java字节码的类库.是由东京技术学院的数学和计算机科学系的 Shigeru Chiba 所创建的.它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态AOP框架. BCEL  Byte Code Engineering Library (BCEL),这是Apache Software Foundation 的Jakarta 项目的一部分.BCEL是 Java classwor

JAVA使用和操作properties文件

java中的properties文件是一种配置文件,主要用于表达配置信息,文件类型为*.properties,格式为文本文件,文件的内容是格式是"键=值"的格式,在properties文件中,可以用"#"来作注释,properties文件在Java编程中用到的地方很多,操作很方便.Properties 类存在于包 Java.util 中,该类继承自 Hashtable. 1. getProperty ( String  key) ,   用指定的键在此属性列表中搜索

防止远程操作中断的杀手工具--GNUScreen

参考链接 ("开源慕课平台") 场景描述 系统管理员经常通过ssh或者telnet远程登录到Linux服务器来进行远程管理,需要运行一些需要很长时间才能完成的任务,必须等待他们执行完毕,比如远程操作备份,或者传输一些大的文件.如果需要临时断开,或者发生意外网络中断和终端意外断开,你正在执行的任务就会被kill掉. 为了解决这样的问题,GNU screen就是防止这种情况的一种方法. 什么是screen screen是GNU计划中用于命令行终端切换的自由软件,用户可以通过连接多个本地或者

Git远程操作详解

Git是目前最流行的版本管理系统,学会Git几乎成了开发者的必备技能. Git有很多优势,其中之一就是远程操作非常简便.本文详细介绍5个Git命令,它们的概念和用法,理解了这些内容,你就会完全掌握Git远程操作. git clone git remote git fetch git pull git push 本文针对初级用户,从最简单的讲起,但是需要读者对Git的基本用法有所了解.同时,本文覆盖了上面5个命令的几乎所有的常用用法,所以对于熟练用户也有参考价值. 一.git clone 远程操作

攻城狮在路上(叁)Linux(二十六)--- linux文件系统的特殊查看与操作

一.boot sector 与 super block的关系: 1.boot sector用于存放引导装载程序,占用1024个字节. 2.super block的大小也为1024字节. 3.若block大小为1k,则boot sector和super block各占一个block. 4.若block大于1K(2K/4K)时,则两者都位于第一个block中. 二.磁盘空间的浪费问题:暂不考虑. 三.利用GUN的parted命令进行分区行为: 因为fdisk不支持高于2TB的分区. 命令格式: pa