• Jar包:apache的commons-net包;
  • 支持断点续传
  • 支持进度监控(有时出不来,搞不清原因)

相关知识点

  • 编码格式: UTF-8等;
  • 文件类型: 包括[BINARY_FILE_TYPE(常用)]和[ASCII_FILE_TYPE]两种;
  • 数据连接模式:一般使用LocalPassiveMode模式,因为大部分客户端都在防火墙后面;
              1. LocalPassiveMode:服务器端打开数据端口,进行数据传输;
              2. LocalActiveMode:客户端打开数据端口,进行数据传输;
  • 系统类型:UNIX/WINDOWS等,默认为Unix

流程

  • 步骤1: 创建FTPClient对象,设置ftpClient属性:如编码格式、连接超时、文件上传下载进度监听器等;
  • 步骤2: 使用ftpClient连接远程server:connect();
  • 步骤3: 获取connect()的返回码getReplyCode(),判断是否连接成功:isPositiveCompletion();
  • 步骤4: 登录远程server:login(),并转到相应目录,必要时要递归创建目录;
  • 步骤5: 设置ftpClient属性:如缓存大小、文件类型、超时时间、数据连接模式等;
  • 步骤6: ftp相关操作:如文件上传、下载等;
  • 步骤7: 断开连接,释放资源:logout()/disconnect();

程序

FTP连接和登录



文件上传



文件下载


测试程序


完整程序

  1. package com.sssppp.Communication;
  2. import java.io.File;
  3. import java.io.FileOutputStream;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.io.OutputStream;
  7. import java.io.PrintWriter;
  8. import java.io.RandomAccessFile;
  9. import org.apache.commons.net.PrintCommandListener;
  10. import org.apache.commons.net.ftp.FTP;
  11. import org.apache.commons.net.ftp.FTPClient;
  12. import org.apache.commons.net.ftp.FTPClientConfig;
  13. import org.apache.commons.net.ftp.FTPFile;
  14. import org.apache.commons.net.ftp.FTPReply;
  15. import org.apache.commons.net.io.CopyStreamEvent;
  16. import org.apache.commons.net.io.CopyStreamListener;
  17. /**
  18. * FTP进行文件上传和下载;
  19. * 支持断点续传;
  20. */
  21. public final class FTPUtil {
  22. private final FTPClient ftp = new FTPClient();
  23. /**
  24. *
  25. * @param hostname
  26. * 如:IP
  27. * @param port
  28. * @param username
  29. * @param password
  30. * @return
  31. * @throws IOException
  32. */
  33. public boolean connect(String hostname, int port, String username,
  34. String password) throws IOException {
  35. boolean debug = false;
  36. if (debug) {
  37. // 设置将过程中使用到的命令输出到控制台
  38. this.ftp.addProtocolCommandListener(new PrintCommandListener(
  39. new PrintWriter(System.out), true));
  40. }
  41. //设置系统类型
  42. final FTPClientConfig config = new FTPClientConfig(
  43. FTPClientConfig.SYST_UNIX);
  44. this.ftp.configure(config);
  45. try {
  46. this.ftp.connect(hostname, port);
  47. if (!FTPReply.isPositiveCompletion(this.ftp.getReplyCode())) {
  48. this.ftp.disconnect();
  49. System.err.println("FTP server refused connection.");
  50. return false;
  51. }
  52. } catch (IOException e) {
  53. if (this.ftp.isConnected()) {
  54. try {
  55. this.ftp.disconnect();
  56. } catch (IOException f) {
  57. }
  58. }
  59. System.err.println("Could not connect to server.");
  60. e.printStackTrace();
  61. return false;
  62. }
  63. if (!this.ftp.login(username, password)) {
  64. this.ftp.logout();
  65. System.err.println("Could not login to server.");
  66. return false;
  67. }
  68. return true;
  69. }
  70. public void disconnect() throws IOException {
  71. if (this.ftp.isConnected()) {
  72. try {
  73. this.ftp.logout();
  74. this.ftp.disconnect();
  75. } catch (IOException f) {
  76. }
  77. }
  78. }
  79. /**
  80. *
  81. * @param absSrcFileName
  82. * @param destDir
  83. * @param destFileName
  84. * @throws IOException
  85. */
  86. public void upLoadByFtp(String absSrcFileName, String destDir,
  87. String destFileName) throws IOException {
  88. // 创建并转到工作目录
  89. String absDstDir = this.ftp.printWorkingDirectory() + "/" + destDir;
  90. absDstDir = absDstDir.replaceAll("//", "/");
  91. createDirectory(absDstDir, this.ftp);
  92. // 设置各种属性
  93. this.ftp.setFileType(FTP.BINARY_FILE_TYPE);
  94. // Use passive mode as default because most of us are behind firewalls these days.
  95. this.ftp.enterLocalPassiveMode();
  96. this.ftp.setControlEncoding("utf-8");
  97. this.ftp.setBufferSize(1024);
  98. // 进度监听
  99. File srcFile = new File(absSrcFileName);
  100. this.ftp.setCopyStreamListener(new MyCopyStreamListener(srcFile.length()));
  101. FTPFile[] files = this.ftp.listFiles(destFileName);
  102. if (files.length == 1) {// 断点续传
  103. long dstFileSize = files[0].getSize();
  104. if (srcFile.length() <= dstFileSize) {// 文件已存在
  105. return;
  106. }
  107. boolean b = uploadFile(destFileName, srcFile, this.ftp, dstFileSize);
  108. if (!b) {// 如果断点续传没有成功,则删除服务器上文件,重新上传
  109. if (this.ftp.deleteFile(destFileName)) {
  110. uploadFile(destFileName, srcFile, this.ftp, 0);
  111. }else {
  112. System.err.println("Delete file fail.");
  113. }
  114. }
  115. } else {
  116. uploadFile(destFileName, srcFile, this.ftp, 0);
  117. }
  118. }
  119. /**
  120. *
  121. * @param remoteFileName
  122. * @param localFileName
  123. * @throws IOException
  124. */
  125. public void downLoadByFtp(String remoteFileName, String localFileName)
  126. throws IOException {
  127. InputStream input = null;
  128. FileOutputStream fos = null;
  129. // 设置各种属性
  130. this.ftp.setBufferSize(1024);
  131. this.ftp.setDataTimeout(1000 * 10);
  132. this.ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
  133. this.ftp.enterLocalPassiveMode();
  134. // 判断远程文件是否存在
  135. FTPFile[] files = this.ftp.listFiles(remoteFileName);
  136. if (files.length != 1) {
  137. System.err.println("Remote file not exist.");
  138. return;
  139. }
  140. //进度监听
  141. long remoteSize = files[0].getSize();
  142. this.ftp.setCopyStreamListener(new MyCopyStreamListener(remoteSize));
  143. File file = new File(localFileName);
  144. if (file.exists()) {
  145. long localSize = file.length();
  146. if (localSize >= remoteSize) {
  147. return;
  148. }
  149. System.out.println("@@@Break point download.@@@");
  150. fos = new FileOutputStream(file, true);// append模式
  151. this.ftp.setRestartOffset(localSize);
  152. } else {
  153. fos = new FileOutputStream(file); // override模式
  154. }
  155. input = this.ftp.retrieveFileStream(remoteFileName);
  156. byte[] b = new byte[8192];
  157. int n = 0;
  158. while (-1 != (n = input.read(b))) {
  159. if (Thread.currentThread().isInterrupted()) {
  160. break;
  161. }
  162. fos.write(b, 0, n);
  163. }
  164. if (input != null) {
  165. input.close();
  166. }
  167. if (fos != null) {
  168. fos.flush();
  169. fos.close();
  170. }
  171. if (!this.ftp.completePendingCommand()) {
  172. System.err.println("Download file fail.");
  173. this.ftp.logout();
  174. this.ftp.disconnect();
  175. }
  176. }
  177. /**
  178. *
  179. * @param destFileName
  180. * @param srcFile
  181. * @param ftpClient
  182. * @param dstFileSize 文件写入的起始位置; >0:表示断点续传,<=0:表示上传新文件
  183. * @return
  184. * @throws IOException
  185. */
  186. private boolean uploadFile(String destFileName, File srcFile,
  187. FTPClient ftpClient, long dstFileSize) throws IOException {
  188. RandomAccessFile input = null;
  189. OutputStream fout = null;
  190. input = new RandomAccessFile(srcFile, "r"); // 只读模式
  191. if (dstFileSize > 0) {// 断点续传
  192. fout = ftpClient.appendFileStream(destFileName);
  193. input.seek(dstFileSize);
  194. ftpClient.setRestartOffset(dstFileSize);
  195. } else {
  196. fout = ftpClient.storeFileStream(destFileName);
  197. }
  198. byte[] b = new byte[8192]; // 缓存大小
  199. int n = 0;
  200. while (-1 != (n = input.read(b))) {
  201. if (Thread.currentThread().isInterrupted()) {
  202. break;
  203. }
  204. fout.write(b, 0, n);
  205. }
  206. if (input != null) {
  207. input.close();
  208. }
  209. if (fout != null) {
  210. fout.flush();
  211. fout.close();
  212. }
  213. if (!ftpClient.completePendingCommand()) {
  214. System.err.println("Upload file fail.");
  215. ftpClient.logout();
  216. ftpClient.disconnect();
  217. return false;
  218. }
  219. return true;
  220. }
  221. /**
  222. * 在FTP服务器上创建并转到工作目录
  223. *
  224. * @param relativePath
  225. * 相对工作路径,不包含文件名:如 dd/11/22/33
  226. * @param ftpClient
  227. * 录创建是否成功
  228. * @return
  229. * @throws IOException
  230. */
  231. private boolean createDirectory(String relativePath, FTPClient ftpClient)
  232. throws IOException {
  233. if (!relativePath.startsWith("/")) {
  234. relativePath = "/" + relativePath;
  235. }
  236. String dir = (ftpClient.printWorkingDirectory().equals("/") ? ""
  237. : ftpClient.printWorkingDirectory()) + relativePath;
  238. if (!ftpClient.changeWorkingDirectory(dir)) {
  239. //目录不存在,则创建各级目录
  240. for (String subDir : relativePath.split("/")) {
  241. if (!subDir.equals("")) {
  242. String newDir = ftpClient.printWorkingDirectory() + "/"
  243. + subDir;
  244. ftpClient.mkd(newDir);
  245. if (!ftpClient.changeWorkingDirectory(newDir)) {
  246. return false;
  247. }
  248. }
  249. }
  250. }
  251. return true;
  252. }
  253. /**
  254. * 进度监听器
  255. */
  256. private class MyCopyStreamListener implements CopyStreamListener {
  257. private long totalSize = 0;
  258. private long percent = -1; // 进度
  259. /**
  260. * 文件的总大小
  261. * @param totalSize
  262. */
  263. public MyCopyStreamListener(long totalSize) {
  264. super();
  265. this.totalSize = totalSize;
  266. }
  267. @Override
  268. public void bytesTransferred(CopyStreamEvent event) {
  269. bytesTransferred(event.getTotalBytesTransferred(),
  270. event.getBytesTransferred(), event.getStreamSize());
  271. }
  272. //totalBytesTransferred:当前总共已传输字节数;
  273. //bytesTransferred:最近一次传输字节数
  274. @Override
  275. public void bytesTransferred(long totalBytesTransferred,
  276. int bytesTransferred, long streamSize) {
  277. if (percent >= totalBytesTransferred * 100 / totalSize) {
  278. return;
  279. }
  280. percent = totalBytesTransferred * 100 / totalSize;
  281. System.out.println("Completed " + totalBytesTransferred + "("
  282. + percent + "%) out of " + totalSize + ".");
  283. }
  284. }
  285. public static void main(String[] args) throws IOException {
  286. String hostname = "10.180.137.241";
  287. String username = "xxx";
  288. String password = "xxx";
  289. int port = 21;
  290. FTPUtil ftp = new FTPUtil();
  291. //上传文件
  292. String absSrcFileName = "C:\\tmp\\m2eclipse1.zip";
  293. String destDir = "ww/11/22/33";
  294. String destFileName = "m2eclipse1.zip";
  295. ftp.connect(hostname, port, username, password);
  296. ftp.upLoadByFtp(absSrcFileName, destDir, destFileName);
  297. ftp.disconnect();
  298. // 下载文件
  299. String localFileName = "C:\\tmp\\m2eclipse-download3333.zip";
  300. String remoteFileName = "/ww/11/22/33/m2eclipse.zip";
  301. ftp.connect(hostname, port, username, password);
  302. ftp.downLoadByFtp(remoteFileName, localFileName);
  303. ftp.disconnect();
  304. }
  305. }

参考链接



【FTP】FTP文件上传下载-支持断点续传的更多相关文章

  1. FTP文件上传并支持断点续传(一)—— win10 本地环境 ftp站点构建

    由于之前项目开发是采用是采用的FTP文件上传,就一直想学习,但由于FTP服务器是公司的,为了方便就像把本地变成ftp站点,其实很简单,但也有很多坑 这里简单介绍一下自己遇到的坑 一:开通本地的ftp权 ...

  2. PHP 大文件上传,支持断点续传,求具体方案、源码或者文件上传插件

    文件夹数据库处理逻辑 publicclass DbFolder { JSONObject root; public DbFolder() { this.root = new JSONObject(); ...

  3. ftp实现文件上传(下载)

    例子代码 package getUrlPic; import java.io.ByteArrayInputStream; import java.io.IOException; import java ...

  4. 转:【专题十一】实现一个基于FTP协议的程序——文件上传下载器

    引言: 在这个专题将为大家揭开下FTP这个协议的面纱,其实学习知识和生活中的例子都是很相通的,就拿这个专题来说,要了解FTP协议然后根据FTP协议实现一个文件下载器,就和和追MM是差不多的过程的,相信 ...

  5. Java实现FTP批量大文件上传下载篇1

    本文介绍了在Java中,如何使用Java现有的可用的库来编写FTP客户端代码,并开发成Applet控件,做成基于Web的批量.大文件的上传下载控件.文章在比较了一系列FTP客户库的基础上,就其中一个比 ...

  6. Python 基于Python实现Ftp文件上传,下载

    基于Python实现Ftp文件上传,下载   by:授客 QQ:1033553122 测试环境: Ftp客户端:Windows平台 Ftp服务器:Linux平台 Python版本:Python 2.7 ...

  7. 专题十一:实现一个基于FTP协议的程序——文件上传下载器

    引言: 在这个专题将为大家揭开下FTP这个协议的面纱,其实学习知识和生活中的例子都是很相通的,就拿这个专题来说,要了解FTP协议然后根据FTP协议实现一个文件下载器,就和和追MM是差不多的过程的,相信 ...

  8. 【ABAP系列】SAP ABAP 实现FTP的文件上传与下载

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP 实现FTP的文 ...

  9. HTTP文件上传服务器-支持超大文件HTTP断点续传的实现办法

    最近由于笔者所在的研发集团产品需要,需要支持高性能的大文件http上传,并且要求支持http断点续传.笔者在以前的博客如何实现支持大文件的高性能HTTP文件上传服务器已经介绍了实现大文件上传的一些基本 ...

随机推荐

  1. canvas转盘抽奖

    1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" ...

  2. vim 分屏显示

    我用vim打开一个文件后,想同时打开另一个文件,就像windows中打开两个记事本一样,因此需要分屏显示 首先用vim打开一个文件 vim file1 输入命令[Esc] :sp file2 分屏打开 ...

  3. 兼容解决 IE 、火狐、谷歌浏览器中 Iframe框架的页面缓存的方法

    <script type="text/javascript"> document.write('<iframe src="/ad_footer.html ...

  4. 深入理解css系列:css定位

    一.概述 1.默认文档流定位方式 (1).HTML默认文档以流模式定位,即内容元素按照先后顺序依次上下定位: (2).HTML标签元素总体分为块状元素.内联元素.内联块状元素,可通过该标签对应的DOM ...

  5. 信号量与PV操作

    在计算机操作系统中,PV操作是进程管理中的难点.首先应弄清PV操作的含义:PV操作由P操作原语和V操作原语组成(原语是不可中断的过程),对信号量进行操作,具体定义如下:    P(S):①将信号量S的 ...

  6. C#常用操作类库五(电脑操作类)

    /// <summary> /// Computer Information /// </summary> public class ComputerHelper { publ ...

  7. Microsoft Visual C++

    Microsoft Visual C++ Visual C++ 1.0 1992 Visual C++ 1.5 Visual C++ 2.0 (备注) Visual C++ 4.0 Visual C+ ...

  8. 最全的CSS浏览器兼容问题

    CSS对浏览器的兼容性有时让人很头疼,或许当你了解当中的技巧跟原理,就会觉得也不是难事,从网上收集了IE7,6与Fireofx的兼容性处理方法并整理了一下.对于web2.0的过度,请尽量用xhtml格 ...

  9. powerdesigner 生成mysql PDM 的COMMENT注释

    1powerdesigner 生成mysql PDM 的COMMENT注释 默认的pd没有生成注释,针对mysql5.0可以如下修改.在Database-->edit Current DBMS. ...

  10. Hql 中 dao 层 以及daoimpl 层的代码,让mvc 模式更直观简洁

    1.BaseDao接口: //使用BaseDao<T> 泛型 ,在service中注入的时候,只需要将T换为对应的bean即可 public interface BaseDao<T& ...