首页 > 代码库 > 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多线程,断点续传上传下载
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。