首页 > 代码库 > FTP多线程,断点续传上传下载

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(remote123                     .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(remote150                     .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 local183      *            本地文件名称,绝对路径184      * @param remote185      *            远程文件路径,使用/home/directory1/subdirectory/file.ext或是186      *            http://www.guihua.org /subdirectory/file.ext187      *            按照Linux上的路径指定方式,支持多级目录嵌套,支持递归创建不存在的目录结构188      * @return 上传结果189      * @throws IOException190      */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(remoteFileName210                 .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 IOException241      */242     public void disconnect() throws IOException {243         if (ftpClient.isConnected()) {244             ftpClient.disconnect();245         }246     }247 248     /**249      * 递归创建远程服务器目录250      * 251      * @param remote252      *            远程服务器文件绝对路径253      * @param ftpClient254      *            FTPClient 对象255      * @return 目录创建是否成功256      * @throws IOException257      */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(directory264                         .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 remoteFile301      *            远程文件名,在上传之前已经将服务器工作目录做了改变302      * @param localFile303      *            本地文件 File句柄,绝对路径304      * @param processStep305      *            需要显示的处理进度步进值306      * @param ftpClient307      *            FTPClient 引用308      * @return309      * @throws IOException310      */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(remoteFile320                 .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_Success344                     : UploadStatus.Upload_From_Break_Failed;345         } else {346             status = result ? UploadStatus.Upload_New_File_Success347                     : 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 }

 

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