这个就看代码,哈哈哈哈哈  需要用到的jar包是:

  1. <dependency>
  2. <groupId>commons-net</groupId>
  3. <artifactId>commons-net</artifactId>
  4. <version>3.3</version>
  5. </dependency>

一:定义我们可能会返回的状态值。两个枚举类 一个异常类

  1. public enum UploadStatus {
  2. Create_Directory_Fail, //远程服务器相应目录创建失败
  3. Create_Directory_Success, //远程服务器闯将目录成功
  4. Upload_New_File_Success, //上传新文件成功
  5. Upload_New_File_Failed, //上传新文件失败
  6. File_Exits, //文件已经存在
  7. Remote_Bigger_Local, //远程文件大于本地文件
  8. Upload_From_Break_Success, //断点续传成功
  9. Upload_From_Break_Failed, //断点续传失败
  10. Delete_Remote_Faild; //删除远程文件失败
  11. }
  1. public enum DownloadStatus {
  2. Remote_File_Noexist, //远程文件不存在
  3. Local_Bigger_Remote, //本地文件大于远程文件
  4. Download_From_Break_Success, //断点下载文件成功
  5. Download_From_Break_Failed, //断点下载文件失败
  6. Download_New_Success, //全新下载文件成功
  7. Download_New_Failed; //全新下载文件失败
  8. }

//用于记录创建时候的异常

  1. public class CreateException extends Exception{
  2. private static Logger log = LoggerFactory.getLogger(CreateException.class);
  3. private static final long serialVersionUID = 1L;
  4.  
  5. private Integer errCode;
  6. private String errMessage;
  7.  
  8. public CreateException(Throwable cause, Integer errCode, String errMessage) {
  9. super(cause);
  10. this.errCode = errCode;
  11. this.errMessage = errMessage;
  12. }
  13.  
  14. public CreateException(Integer errCode, String errMessage) {
  15. this.errCode = errCode;
  16. this.errMessage = errMessage;
  17. }
  18. public CreateException(Integer errCode, UploadStatus uploadStatus) {
  19. this.errCode = errCode;
  20. this.errMessage = uploadStatus.toString();
  21. }
  22.  
  23. public Integer getErrCode() {
  24. return errCode;
  25. }
  26.  
  27. public String getErrMessage() {
  28. return errMessage;
  29. }
  30. }

二:创建连接ftp服务器的类

  1. package com.utils.study.ftpCenter;
  2.  
  3. import com.coocaa.core.generation.service.CreateBeanService;
  4. import org.apache.commons.net.PrintCommandListener;
  5. import org.apache.commons.net.ftp.FTP;
  6. import org.apache.commons.net.ftp.FTPClient;
  7. import org.apache.commons.net.ftp.FTPReply;
  8. import org.slf4j.Logger;
  9. import org.slf4j.LoggerFactory;
  10.  
  11. import java.io.IOException;
  12. import java.io.PrintWriter;
  13.  
  14. /**
  15. * Created by yugaofeng on 2017/9/5.
  16. */
  17. public class ContinueFTP {
  18. private static Logger logger = LoggerFactory.getLogger(CreateBeanService.class);
  19.  
  20. //定义一个客户端
  21. private static FTPClient ftpClient ;
  22.  
  23. //单例模式
  24. public FTPClient getFtpClient(){
  25. if(ftpClient == null){
  26. ftpClient = new FTPClient();
  27. }
  28. return ftpClient;
  29. }
  30.  
  31. public ContinueFTP(){
  32. getFtpClient().addProtocolCommandListener(new PrintCommandListener(
  33. new PrintWriter(System.out)));
  34. }
  35.  
  36. /**
  37. * 连接到FTP服务器
  38. * @param hostname 主机名
  39. * @param port 端口
  40. * @param username 用户名
  41. * @param password 密码
  42. * @return 是否连接成功
  43. * @throws IOException
  44. */
  45. public boolean connect(String hostname, int port, String username, String password) throws IOException {
  46. getFtpClient().connect(hostname, port);
  47. if (FTPReply.isPositiveCompletion(getFtpClient().getReplyCode())) {
  48. if (getFtpClient().login(username, password)) {
  49. getFtpClient().enterLocalPassiveMode();
  50. getFtpClient().setFileType(FTP.BINARY_FILE_TYPE);
  51. return true;
  52. }
  53. }
  54. disconnect();
  55. return false;
  56. }
  57.  
  58. /**
  59. * 断开与服务器的连接
  60. * @throws IOException
  61. */
  62. public void disconnect() throws IOException {
  63. if (getFtpClient().isConnected()) {
  64. getFtpClient().disconnect();
  65. System.out.println("ftp is disconnect!");
  66. }
  67. }
  68. }

这个时候 先测试一下 你能不能连接到服务器

  1. public static void main(String[] args) throws IOException {
  2. ContinueFTP ftp = new ContinueFTP();
  3.  
  4. System.out.println("<<<<<<<<<<<<<<<<<1"+ftp.getFtpClient().isConnected());
  5. ftp.connect("172.20.139.217", 21, "ftp01", "ftp111");
  6. System.out.println("<<<<<<<<<<<<<<<<<3"+ftp.getFtpClient().isConnected());
  7. ftp.getFtpClient().disconnect();
  8. }

表示连接成功

三:实现文件上传 和断点续传

由于设置了观察者 在观察当前上传的进度变化 ,本次代码中 没有添加观察者模式的代码,所以这个地方 可能需要先注释掉观察者

  1. package com.utils.study.ftpCenter;
  2.  
  3. import com.utils.study.CreateException;
  4. import com.utils.study.enums.UploadStatus;
  5. import com.utils.study.observerModel.FileObserverAble;
  6. import com.utils.study.observerModel.FilePercentObserver;
  7. import org.apache.commons.net.ftp.FTPClient;
  8. import org.apache.commons.net.ftp.FTPFile;
  9.  
  10. import java.io.*;
  11.  
  12. /**
  13. * Created by yugaofeng on 2017/9/5.
  14. */
  15. public class FileOperateByFtp {
  16.  
  17. private FTPClient ftpClient;
  18.  
  19. FileObserverAble fileObserverAble;
  20.  
  21. public FileOperateByFtp(FTPClient ftpClient) {
  22. //添加观察者对象
  23. fileObserverAble = new FileObserverAble();
  24. FilePercentObserver filePercentObserver = new FilePercentObserver(fileObserverAble);
  25. this.ftpClient = ftpClient;
  26. }
  27.  
  28. /**
  29. * 上传文件到FTP服务器,支持断点续传 并返回上传文件进度
  30. * @param local 本地文件名称,绝对路径
  31. * @param remote 远程文件路径,使用/home/directory1/subdirectory/file.ext
  32. * 按照Linux上的路径指定方式,支持多级目录嵌套,支持递归创建不存在的目录结构
  33. * @return 上传结果
  34. * @throws IOException
  35. */
  36. public UploadStatus upload(String local, String remote) throws Exception{
  37. try {
  38. if (!ftpClient.isConnected()) {
  39. throw new CreateException(-1, "远程服务器相应目录创建失败");
  40. }
  41. UploadStatus result;
  42. // 对远程目录的处理 并返回文件的名称
  43. String remoteFileName = createDirectory(remote, ftpClient);
  44. // 检查远程是否存在文件
  45. FTPFile[] files = ftpClient.listFiles(remoteFileName);
  46. File localFile = new File(local);
  47. if(localFile.length() <=0){
  48. throw new CreateException(-1,"本地文件不存在");
  49. }
  50. if (files.length == 1) {
  51. //判断文件是否存在
  52. long remoteSize = files[0].getSize();
  53. long localSize = localFile.length();
  54. if(remoteSize==localSize){
  55. return UploadStatus.File_Exits;
  56. }else if(remoteSize > localSize){
  57. return UploadStatus.Remote_Bigger_Local;
  58. }
  59. result = this.writeByUnit(remoteFileName,localFile,ftpClient,remoteSize,localFile.length());
  60. } else {
  61. result = this.writeByUnit(remoteFileName,localFile,ftpClient,0,localFile.length());
  62. }
  63. return result;
  64. }catch (CreateException e){
  65. throw e;
  66. }finally {
  67. //上传完成之后 切回到根目录
  68. ftpClient.changeWorkingDirectory("/");
  69. }
  70. }
  71.  
  72. /**
  73. * 判断目录
  74. * @param remoteFilePath 远程服务器上面的 文件目录
  75. * @param ftpClient ftp客户端
  76. * @return
  77. * @throws Exception
  78. */
  79. private String createDirectory(String remoteFilePath,FTPClient ftpClient) throws Exception {
  80. if(ftpClient == null){
  81. throw new CreateException(-1,"FTP客户端为空,请先连接到客户端");
  82. }
  83. String fileName = remoteFilePath;
  84. if(remoteFilePath.contains("/")){
  85. fileName = remoteFilePath.substring(remoteFilePath.lastIndexOf("/") + 1);
  86. String directory = remoteFilePath.substring(0, remoteFilePath.lastIndexOf("/") + 1);
  87. if(directory.startsWith("/")){
  88. directory = directory.substring(1);
  89. }
  90. while (true){
  91. if(!directory.contains("/")){
  92. break;
  93. }
  94. String subDirectory = directory.substring(0, directory.indexOf("/"));
  95. directory = directory.substring(directory.indexOf("/")+1);
  96. if (!ftpClient.changeWorkingDirectory(subDirectory)) {
  97. if (ftpClient.makeDirectory(subDirectory)) {
  98. ftpClient.changeWorkingDirectory(subDirectory);
  99. } else {
  100. throw new CreateException(-1,"创建目录失败");
  101. }
  102. }
  103. }
  104. }
  105. return fileName;
  106. }
  107.  
  108. /**
  109. * 上传文件到服务器,新上传和断点续传
  110. * @param remoteFile 远程文件名,在上传之前已经将服务器工作目录做了改变
  111. * @param localFile 本地文件File句柄,绝对路径
  112. * @param ftpClient FTPClient引用 beginSize是指文件长传开始指针位置 endSize是结束的位置 为多线程上传下载提供接口 不过该方法还需要修改
  113. * @return
  114. * @throws IOException
  115. */
  116.  
  117. private UploadStatus writeByUnit(String remoteFile,File localFile,FTPClient ftpClient,long beginSize,long endSize) throws Exception {
  118. long localSize = localFile.length();
  119. if(endSize > localSize){
  120. endSize = localSize;
  121. }
  122. if(beginSize < 0){
  123. beginSize = 0;
  124. }
  125. //等待写入的文件大小
  126. long writeSize = endSize - beginSize;
  127. if(writeSize <= 0){
  128. throw new CreateException(1,"文件指针参数出错");
  129. }
  130. //获取百分单位是 1-100
  131. RandomAccessFile raf = new RandomAccessFile(localFile,"r");
  132. OutputStream out = ftpClient.appendFileStream(new String(remoteFile.getBytes("GBK"),"iso-8859-1"));
  133. //把文件指针移动到 开始位置
  134. ftpClient.setRestartOffset(beginSize);
  135. raf.seek(beginSize);
  136. //定义最小移动单位是 1024字节 也就是1kb
  137. byte[] bytes = new byte[1024];
  138. int c;
  139. double finishSize = 0;
  140. double finishPercent = 0;
  141. //存在一个bug 当分布移动的时候 可能会出现下载重复的问题 后期需要修改
  142. while ((c = raf.read(bytes)) != -1) {
  143. out.write(bytes, 0, c);
  144. finishSize += c;
  145. if(finishSize > writeSize){
  146. finishPercent = 1;
  147. //System.out.println(">>>>>完成进度:" + finishPercent);
  148. fileObserverAble.setKeyValue(localFile.getName(),finishPercent,"upload");
  149. break;
  150. }
  151. if ((finishSize / writeSize) - finishPercent > 0.01) {
  152. finishPercent = finishSize / writeSize;
  153. //System.out.println(">>>>>完成进度:" + finishPercent);
  154. fileObserverAble.setKeyValue(localFile.getName(),finishPercent,"upload");
  155. }
  156. }
  157. out.flush();
  158. raf.close();
  159. out.close();
  160. boolean result =ftpClient.completePendingCommand();
  161. return result?UploadStatus.Upload_From_Break_Success:UploadStatus.Upload_From_Break_Failed;
  162. }
  163.  
  164. /**
  165. * 从FTP服务器上下载文件
  166. * @param remote 远程文件路径
  167. * @param local 本地文件路径
  168. * @return 是否成功
  169. * @throws IOException
  170. */
  171. public boolean download(String remote,String local) throws Exception{
  172. FTPFile[] files = ftpClient.listFiles(remote);
  173. if(files == null || files.length < 0){
  174. throw new CreateException(-1,"远程文件不存在");
  175. }
  176. if(files.length != 1){
  177. throw new CreateException(-1,"远程文件不唯一");
  178. }
  179. File localFile = new File(local);
  180. if(localFile.exists()){
  181. long localBeginSize = localFile.length();
  182. if(localBeginSize == files[0].getSize()){
  183. throw new CreateException(-1,"文件已经存在");
  184. }else if(localBeginSize > files[0].getSize()){
  185. throw new CreateException(-1,"下载文件出错");
  186. }
  187. return downloadByUnit(remote,local,localBeginSize,files[0].getSize());
  188. }else {
  189. return downloadByUnit(remote,local,0,files[0].getSize());
  190. }
  191. }
  192. private Boolean downloadByUnit(String remote,String local,long beginSize,long endSize) throws Exception {
  193. File localFile = new File(local);
  194. long waitSize = endSize - beginSize;
  195. //进行断点续传,并记录状态
  196. FileOutputStream out = new FileOutputStream(localFile,true);
  197. //把文件指针移动到 开始位置
  198. ftpClient.setRestartOffset(beginSize);
  199. InputStream in = ftpClient.retrieveFileStream(new String(remote.getBytes("GBK"),"iso-8859-1"));
  200. byte[] bytes = new byte[1024];
  201. int c;
  202. double finishSize =0;
  203. double finishPercent = 0;
  204. while((c = in.read(bytes))!= -1){
  205. out.write(bytes,0,c);
  206. finishSize += c;
  207. if(finishSize > waitSize){
  208. //System.out.println(">>>>>完成进度:" + 1);
  209. fileObserverAble.setKeyValue(localFile.getName(),1,"download");
  210.  
  211. }
  212. if ((finishSize / waitSize) - finishPercent > 0.01) {
  213. finishPercent = finishSize / waitSize;
  214. //System.out.println(">>>>>完成进度:" + finishPercent);
  215. fileObserverAble.setKeyValue(localFile.getName(),finishPercent,"download");
  216. }
  217. }
  218. in.close();
  219. out.close();
  220. return ftpClient.completePendingCommand();
  221. }
  222.  
  223. }

测试上传 并在控制台打印出 上传百分百

  1. public static void main(String[] args) {
  2. ContinueFTP ftp = new ContinueFTP();
  3. try {
  4. ftp.connect("172.20.139.217", 21, "ftp01", "ftp111");
  5. FileOperateByFtp fileOperateByFtp = new FileOperateByFtp(ftp.getFtpClient());
  6. fileOperateByFtp.upload("F:\\upload7.temp","/upload2/f3/upload7.temp");
  7. fileOperateByFtp.upload("F:\\upload6.temp","/upload2/f3/upload6.temp");
  8. /* fileOperateByFtp.download("/upload2/f3/upload7.temp","F:\\upload6.temp");
  9. fileOperateByFtp.download("//upload2/f3/upload6.temp","F:\\upload7.temp");*/
  10. if(ftp.getFtpClient() != null){
  11. ftp.getFtpClient().disconnect();
  12. }
  13. } catch (Exception e) {
  14. if(e instanceof CreateException){
  15. System.out.println(((CreateException) e).getErrMessage());
  16. }
  17. }
  18.  
  19. }

上传结果:

下载就不做演示

四:总结

 ftp文件长传其实很简单,,实现断点续传也不能
ftp里面提供了一个  ftpClient.setRestartOffset(beginSize); 方法 实现了文件指针移动的开始位置  为后面的 分布式断点 多点上传 提供了 基础 .

另外关于文件显示进度比例,在这里实现也不能,但要是与前端进度条进行实时数据交互式不现实的。。。后来通过查阅资料发现有些还很有道理的。

比如我们服务器一般也会限制文件上传的大小,所以一般显示进度条是在前端做的,通过比较浏览器发送出去的数据量 和带上传的文件大小 进行比较来显示 进度条,但这种方法还没有测试成功,后面会进行验证。

FTP文件上传 支持断点续传 并 打印下载进度(二) —— 单线程实现的更多相关文章

  1. 【SFTP】使用Jsch实现Sftp文件上传-支持断点续传和进程监控

    JSch是Java Secure Channel的缩写.JSch是一个SSH2的纯Java实现.它允许你连接到一个SSH服务器,并且可以使用端口转发,X11转发,文件传输等,当然你也可以集成它的功能到 ...

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

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

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

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

  4. 4GB以上超大文件上传和断点续传服务器的实现

    随着视频网站和大数据应用的普及,特别是高清视频和4K视频应用的到来,超大文件上传已经成为了日常的基础应用需求. 但是在很多情况下,平台运营方并没有大文件上传和断点续传的开发经验,往往在网上找一些简单的 ...

  5. Java实现FTP文件上传与下载

    实现FTP文件上传与下载可以通过以下两种种方式实现(不知道还有没有其他方式),分别为:1.通过JDK自带的API实现:2.通过Apache提供的API是实现. 第一种方式 package com.cl ...

  6. skymvc文件上传支持多文件上传

    skymvc文件上传支持多文件上传 支持单文件.多文件上传 可以设定 文件大小.存储目录.文件类型 //上传的文件目录 $this->upload->uploaddir="att ...

  7. java/struts/Servlet文件下载与ftp文件上传下载

    1.前端代码 使用超链接到Struts的Action或Servlet <a target="_blank" href="ftpFileAction!download ...

  8. .net core版 文件上传/ 支持批量上传,拖拽以及预览,bootstrap fileinput上传文件

    asp.net mvc请移步 mvc文件上传支持批量上传,拖拽以及预览,文件内容校验 本篇内容主要解决.net core中文件上传的问题  开发环境:ubuntu+vscode 1.导入所需要的包:n ...

  9. Java使用comms-net jar包完成ftp文件上传进度的检测功能

    本文章只讲述大致的思路与本次功能对应的一些开发环境,具体实现请结合自己的开发情况,仅供参考,如果有不对的地方,欢迎大家指出! 准备环境:JDK1.7 OR 1.8.eclipse.ftp服务器(可自行 ...

随机推荐

  1. 单机Qps上限是多少?

    现在这个年代,你要是不懂高并发,你都不好意思说自己是搞互联网的! 一.什么是并发,什么是高并发 并发,两个及以上的行为一起发生,比如你一边吃饭一边看电视 高并发,多个行为(至于是多少,这个没有定数,你 ...

  2. Java学习点滴——Integer缓存

    前言 一切从下面这段代码开始 public static void test(String[] agrs){ Integer a = 1; Integer b = 2; System.out.prin ...

  3. css3 动画 总结

    原来的时候写过一个小程序,里面有一个播放背景音乐的按钮(也是一个圆形的图片),它是一直在旋转的,当我们点击这个按钮的可以暂停或者播放背景音乐.当初的这个动画,是同事自己写的,我看到的时候以为是他在上面 ...

  4. EF时,数据库字段和实体类不一致问题

    场景:由于一些原因,实体中属性比数据库中字段多了一个startPage属性.PS:controllers中用实体类去接收参数,但是传入的参数比数据库中实体表多了一个字段, 这种情况下,应该建一个vie ...

  5. 005. [转] SSH端口转发

    玩转SSH端口转发 SSH有三种端口转发模式,本地端口转发(Local Port Forwarding),远程端口转发(Remote Port Forwarding)以及动态端口转发(Dynamic ...

  6. Django 加载 app 中的urls

    在 blog app 下创建 urls.py, 定义该 app 下自有的 url : new/story from blog import views from django.conf import ...

  7. 【AO例子】生成TIN

    当然,通过GP生成也是可以的.这里介绍的是已经烂大街的生成方法. 上代码: public ITin CreateTin(IFeatureClass featureClass, IField Z, st ...

  8. 华途软件受控XML转EXCEL

    公司加密系统用的是华途的产品.最近公司高层想要重新梳理公司信息安全管理情况,华途加密系统的梳理和优化是重中之重. 今天公司领导要求IT导出目前系统中所有软件.后缀的受控情况,然后IT吭哧吭哧地把华途软 ...

  9. process.nextTick

    回调函数同步执行 function asyncFake(data, callback) { if(data === 'foo') { callback(true); }else{ callback(f ...

  10. centos7下给bond网卡配置bridge桥接

    这篇的主题可以用几个关键字组合:centos7+kvm + bond + bridge .brige主要用在KVM虚拟化环境下,而bond是进行物理层面的冗余.具体配置信息如下 物理网卡名称:enp0 ...