FTP多线程,断点续传上传下载

  1 package com.hirain.ftp.thread;
  2 
  3 import java.io.File;
  4 import java.io.FileOutputStream;
  5 import java.io.IOException;
  6 import java.io.InputStream;
  7 import java.io.OutputStream;
  8 import java.io.RandomAccessFile;
  9 
 10 import org.apache.commons.net.ftp.FTP;
 11 import org.apache.commons.net.ftp.FTPClient;
 12 import org.apache.commons.net.ftp.FTPFile;
 13 import org.apache.commons.net.ftp.FTPReply;
 14 
 15 public class FTPDownloadThread extends Thread {
 16 
 17     // 枚举类UploadStatus代码
 18 
 19     public enum UploadStatus {
 20         Create_Directory_Fail, // 远程服务器相应目录创建失败
 21         Create_Directory_Success, // 远程服务器闯将目录成功
 22         Upload_New_File_Success, // 上传新文件成功
 23         Upload_New_File_Failed, // 上传新文件失败
 24         File_Exits, // 文件已经存在
 25         Remote_Bigger_Local, // 远程文件大于本地文件
 26         Upload_From_Break_Success, // 断点续传成功
 27         Upload_From_Break_Failed, // 断点续传失败
 28         Delete_Remote_Faild; // 删除远程文件失败
 29     }
 30 
 31     // 枚举类DownloadStatus代码
 32     public enum DownloadStatus {
 33         Remote_File_Noexist, // 远程文件不存在
 34         Local_Bigger_Remote, // 本地文件大于远程文件
 35         Download_From_Break_Success, // 断点下载文件成功
 36         Download_From_Break_Failed, // 断点下载文件失败
 37         Download_New_Success, // 全新下载文件成功
 38         Download_New_Failed; // 全新下载文件失败
 39     }
 40 
 41     public FTPClient ftpClient = new FTPClient();
 42     private String ftpURL, username, pwd, ftpport, file1, file2;
 43 
 44     public FTPDownloadThread(String _ftpURL, String _username, String _pwd,
 45             String _ftpport, String _file1, String _file2) {
 46         // 设置将过程中使用到的命令输出到控制台
 47         ftpURL = _ftpURL;
 48         username = _username;
 49         pwd = _pwd;
 50         ftpport = _ftpport;
 51         file1 = _file1;
 52         file2 = _file2;
 53     }
 54 
 55     /**
 56      * 连接到FTP服务器
 57      * 
 58      * @param hostname
 59      *            主机名
 60      * @param port
 61      *            端口
 62      * @param username
 63      *            用户名
 64      * @param password
 65      *            密码
 66      * @return 是否连接成功
 67      * @throws IOException
 68      */
 69     public boolean connect(String hostname, int port, String username,
 70             String password) throws IOException {
 71         ftpClient.connect(hostname, port);
 72         ftpClient.setControlEncoding("GBK");
 73         if (FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
 74             if (ftpClient.login(username, password)) {
 75                 return true;
 76             }
 77         }
 78         disconnect();
 79         return false;
 80     }
 81 
 82     /**
 83      * 从FTP服务器上下载文件,支持断点续传,上传百分比汇报
 84      * 
 85      * @param remote
 86      *            远程文件路径
 87      * @param local
 88      *            本地文件路径
 89      * @return 上传的状态
 90      * @throws IOException
 91      */
 92     public DownloadStatus download(String remote, String local)
 93             throws IOException {
 94         // 设置被动模式
 95         ftpClient.enterLocalPassiveMode();
 96         // 设置以二进制方式传输
 97         ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
 98         DownloadStatus result;
 99 
100         // 检查远程文件是否存在
101         FTPFile[] files = ftpClient.listFiles(new String(
102                 remote.getBytes("GBK"), "iso-8859-1"));
103         if (files.length != 1) {
104             System.out.println("远程文件不存在");
105             return DownloadStatus.Remote_File_Noexist;
106         }
107 
108         long remoteSize = files[0].getSize();
109         File f = new File(local);
110         // 本地存在文件,进行断点下载
111         if (f.exists()) {
112             long localSize = f.length();
113             // 判断本地文件大小是否大于远程文件大小
114             if (localSize >= remoteSize) {
115                 System.out.println("本地文件大于远程文件,下载中止");
116                 return DownloadStatus.Local_Bigger_Remote;
117             }
118 
119             // 进行断点续传,并记录状态
120             FileOutputStream out = new FileOutputStream(f, true);
121             ftpClient.setRestartOffset(localSize);
122             InputStream in = ftpClient.retrieveFileStream(new String(remote
123                     .getBytes("GBK"), "iso-8859-1"));
124             byte[] bytes = new byte[1024];
125             long step = remoteSize / 100;
126             long process = localSize / step;
127             int c;
128             while ((c = in.read(bytes)) != -1) {
129                 out.write(bytes, 0, c);
130                 localSize += c;
131                 long nowProcess = localSize / step;
132                 if (nowProcess > process) {
133                     process = nowProcess;
134                     if (process % 10 == 0)
135                         System.out.println("下载进度:" + process);
136                     // TODO 更新文件下载进度,值存放在process变量中
137                 }
138             }
139             in.close();
140             out.close();
141             boolean isDo = ftpClient.completePendingCommand();
142             if (isDo) {
143                 result = DownloadStatus.Download_From_Break_Success;
144             } else {
145                 result = DownloadStatus.Download_From_Break_Failed;
146             }
147         } else {
148             OutputStream out = new FileOutputStream(f);
149             InputStream in = ftpClient.retrieveFileStream(new String(remote
150                     .getBytes("GBK"), "iso-8859-1"));
151             byte[] bytes = new byte[1024];
152             long step = remoteSize / 100;
153             long process = 0;
154             long localSize = 0L;
155             int c;
156             while ((c = in.read(bytes)) != -1) {
157                 out.write(bytes, 0, c);
158                 localSize += c;
159                 long nowProcess = localSize / step;
160                 if (nowProcess > process) {
161                     process = nowProcess;
162                     if (process % 10 == 0)
163                         System.out.println("下载进度:" + process);
164                     // TODO 更新文件下载进度,值存放在process变量中
165                 }
166             }
167             in.close();
168             out.close();
169             boolean upNewStatus = ftpClient.completePendingCommand();
170             if (upNewStatus) {
171                 result = DownloadStatus.Download_New_Success;
172             } else {
173                 result = DownloadStatus.Download_New_Failed;
174             }
175         }
176         return result;
177     }
178 
179     /**
180      * 上传文件到FTP服务器,支持断点续传
181      * 
182      * @param local
183      *            本地文件名称,绝对路径
184      * @param remote
185      *            远程文件路径,使用/home/directory1/subdirectory/file.ext或是
186      *            http://www.guihua.org /subdirectory/file.ext
187      *            按照Linux上的路径指定方式,支持多级目录嵌套,支持递归创建不存在的目录结构
188      * @return 上传结果
189      * @throws IOException
190      */
191     public UploadStatus upload(String local, String remote) throws IOException {
192         // 设置PassiveMode传输
193         ftpClient.enterLocalPassiveMode();
194         // 设置以二进制流的方式传输
195         ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
196         ftpClient.setControlEncoding("GBK");
197         UploadStatus result;
198         // 对远程目录的处理
199         String remoteFileName = remote;
200         if (remote.contains("/")) {
201             remoteFileName = remote.substring(remote.lastIndexOf("/") + 1);
202             // 创建服务器远程目录结构,创建失败直接返回
203             if (CreateDirecroty(remote, ftpClient) == UploadStatus.Create_Directory_Fail) {
204                 return UploadStatus.Create_Directory_Fail;
205             }
206         }
207 
208         // 检查远程是否存在文件
209         FTPFile[] files = ftpClient.listFiles(new String(remoteFileName
210                 .getBytes("GBK"), "iso-8859-1"));
211         if (files.length == 1) {
212             long remoteSize = files[0].getSize();
213             File f = new File(local);
214             long localSize = f.length();
215             if (remoteSize == localSize) {
216                 return UploadStatus.File_Exits;
217             } else if (remoteSize > localSize) {
218                 return UploadStatus.Remote_Bigger_Local;
219             }
220 
221             // 尝试移动文件内读取指针,实现断点续传
222             result = uploadFile(remoteFileName, f, ftpClient, remoteSize);
223 
224             // 如果断点续传没有成功,则删除服务器上文件,重新上传
225             if (result == UploadStatus.Upload_From_Break_Failed) {
226                 if (!ftpClient.deleteFile(remoteFileName)) {
227                     return UploadStatus.Delete_Remote_Faild;
228                 }
229                 result = uploadFile(remoteFileName, f, ftpClient, 0);
230             }
231         } else {
232             result = uploadFile(remoteFileName, new File(local), ftpClient, 0);
233         }
234         return result;
235     }
236 
237     /**
238      * 断开与远程服务器的连接
239      * 
240      * @throws IOException
241      */
242     public void disconnect() throws IOException {
243         if (ftpClient.isConnected()) {
244             ftpClient.disconnect();
245         }
246     }
247 
248     /**
249      * 递归创建远程服务器目录
250      * 
251      * @param remote
252      *            远程服务器文件绝对路径
253      * @param ftpClient
254      *            FTPClient 对象
255      * @return 目录创建是否成功
256      * @throws IOException
257      */
258     public UploadStatus CreateDirecroty(String remote, FTPClient ftpClient)
259             throws IOException {
260         UploadStatus status = UploadStatus.Create_Directory_Success;
261         String directory = remote.substring(0, remote.lastIndexOf("/") + 1);
262         if (!directory.equalsIgnoreCase("/")
263                 && !ftpClient.changeWorkingDirectory(new String(directory
264                         .getBytes("GBK"), "iso-8859-1"))) {
265             // 如果远程目录不存在,则递归创建远程服务器目录
266             int start = 0;
267             int end = 0;
268             if (directory.startsWith("/")) {
269                 start = 1;
270             } else {
271                 start = 0;
272             }
273             end = directory.indexOf("/", start);
274             while (true) {
275                 String subDirectory = new String(remote.substring(start, end)
276                         .getBytes("GBK"), "iso-8859-1");
277                 if (!ftpClient.changeWorkingDirectory(subDirectory)) {
278                     if (ftpClient.makeDirectory(subDirectory)) {
279                         ftpClient.changeWorkingDirectory(subDirectory);
280                     } else {
281                         System.out.println("创建目录失败");
282                         return UploadStatus.Create_Directory_Fail;
283                     }
284                 }
285                 start = end + 1;
286                 end = directory.indexOf("/", start);
287                 // 检查所有目录是否创建完毕
288                 if (end <= start) {
289                     break;
290                 }
291             }
292         }
293         return status;
294     }
295 
296     /** */
297     /**
298      * 上传文件到服务器,新上传和断点续传
299      * 
300      * @param remoteFile
301      *            远程文件名,在上传之前已经将服务器工作目录做了改变
302      * @param localFile
303      *            本地文件 File句柄,绝对路径
304      * @param processStep
305      *            需要显示的处理进度步进值
306      * @param ftpClient
307      *            FTPClient 引用
308      * @return
309      * @throws IOException
310      */
311     public UploadStatus uploadFile(String remoteFile, File localFile,
312             FTPClient ftpClient, long remoteSize) throws IOException {
313         UploadStatus status;
314         // 显示进度的上传
315         long step = localFile.length() / 100;
316         long process = 0;
317         long localreadbytes = 0L;
318         RandomAccessFile raf = new RandomAccessFile(localFile, "r");
319         OutputStream out = ftpClient.appendFileStream(new String(remoteFile
320                 .getBytes("GBK"), "iso-8859-1"));
321         // 断点续传
322         if (remoteSize > 0) {
323             ftpClient.setRestartOffset(remoteSize);
324             process = remoteSize / step;
325             raf.seek(remoteSize);
326             localreadbytes = remoteSize;
327         }
328         byte[] bytes = new byte[1024];
329         int c;
330         while ((c = raf.read(bytes)) != -1) {
331             out.write(bytes, 0, c);
332             localreadbytes += c;
333             if (localreadbytes / step != process) {
334                 process = localreadbytes / step;
335                 System.out.println("上传进度:" + process);
336             }
337         }
338         out.flush();
339         raf.close();
340         out.close();
341         boolean result = ftpClient.completePendingCommand();
342         if (remoteSize > 0) {
343             status = result ? UploadStatus.Upload_From_Break_Success
344                     : UploadStatus.Upload_From_Break_Failed;
345         } else {
346             status = result ? UploadStatus.Upload_New_File_Success
347                     : UploadStatus.Upload_New_File_Failed;
348         }
349         return status;
350     }
351 
352     public void run() {
353         try {
354             this.connect(ftpURL, new java.lang.Integer(ftpport), username, pwd);
355             this.download(file1, file2);
356             this.disconnect();
357         } catch (IOException e) {
358             System.out.println("连接FTP出错:" + e.getMessage());
359         }
360     }
361 
362 }
转载请注明出处,期待共同进步...
原文地址:https://www.cnblogs.com/zhangyukun/p/3992256.html