• 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 }
    转载请注明出处,期待共同进步...
  • 相关阅读:
    GitHub 6大热门实时人脸识别开源项目!哪个最适合初级开发者?
    人脸识别相关开源项目汇总
    Nginx设置成服务并开机自动启动
    Linux安装nginx
    nginx根据域名转发
    14个开源免费的人工智能项目,人脸识别依旧很受欢迎
    linux 双网卡内外网访问
    000webhost – 1500M支持PHP可绑米免费虚拟主机
    CPUID
    Apache中.htaccess文件功能
  • 原文地址:https://www.cnblogs.com/zhangyukun/p/3992256.html
Copyright © 2020-2023  润新知