java 实现ftp断点传输

目录

  1. 需求背景
  2. 原理介绍
  3. 代码实现

1、需求背景

上送交易订单每日达600万,高峰期将近上千万,压缩包高达500M,如果网络上传超时,或者网络出现波动,需要实现断点继续上送功能。

2 原理介绍

那么字面意思,我们已经理解了,实际上ftp断点传输是怎么实现的呢?

实现起来也很简单,每次传输前,先检查下远程文件是否已经存在,如果存在了,那么我们就读取这个文件的大小。然后比较下带传输文件和现在的文件的大小。如果没有现在的文件大,那么可以认为之前上传的文件是完成的,本次不需要上传,但是,现在的文件要是比待上传的文件小的话,就需要重新或者继续上传了。选择继续上传的话,就是断点传输了。

3 代码实现

那么怎么实现这次上传接着上次上传呢?我们都知道,文件操作是有一个文件指针的,每次操作的时候,指针都会移动。因此,如果想实现继续接着上次上传文件,只需要将待上传的文件指针移动一个已经上传的文件的大小即可。明白了原理,代码也就好写了。

import java.io.File;  
 import java.io.FileInputStream;  
 import java.io.FileOutputStream;  
 import java.io.IOException;  
 import java.io.InputStream;  
 import java.io.OutputStream;  
 import java.io.PrintWriter;  
 import org.apache.commons.net.PrintCommandListener;  
 import org.apache.commons.net.ftp.FTP;  
 import org.apache.commons.net.ftp.FTPClient;  
 import org.apache.commons.net.ftp.FTPFile;  
 import org.apache.commons.net.ftp.FTPReply;  
   
 public class ContinueFTP {  
     private FTPClient ftpClient = new FTPClient();  
       
     public ContinueFTP(){  
         //设置将过程中使用到的命令输出到控制台  
         this.ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));  
     }  
       
     /** 
      * java编程中用于连接到FTP服务器    此api最好加一个链接的超时时间
      * @param hostname 主机名 
      * @param port 端口 
      * @param username 用户名 
      * @param password 密码 
      * @return 是否连接成功 
      * @throws IOException 
      */  
     public boolean connect(String hostname,int port,String username,String password) throws IOException{  
         ftpClient.connect(hostname, port);  
         if(FTPReply.isPositiveCompletion(ftpClient.getReplyCode())){  
             if(ftpClient.login(username, password)){  
                 return true;  
             }  
         }  
         disconnect();  
         return false;  
     }  
       
     /** 
      * 从FTP服务器上下载文件 
      * @param remote 远程文件路径 
      * @param local 本地文件路径 
      * @return 是否成功 
      * @throws IOException 
      */  
     public boolean download(String remote,String local) throws IOException{  
         ftpClient.enterLocalPassiveMode();  
         ftpClient.setFileType(FTP.BINARY_FILE_TYPE);  
         boolean result;  
         File f = new File(local);  
         FTPFile[] files = ftpClient.listFiles(remote);  
         if(files.length != 1){  
             System.out.println("远程文件不唯一");  
             return false;  
         }  
         long lRemoteSize = files[0].getSize();  
         if(f.exists()){  
             OutputStream out = new FileOutputStream(f,true);  
             System.out.println("本地文件大小为:"+f.length());  
             if(f.length() >= lRemoteSize){  
                 System.out.println("本地文件大小大于远程文件大小,下载中止");  
                 return false;  
             }  
             ftpClient.setRestartOffset(f.length());  
             result = ftpClient.retrieveFile(remote, out);  
             out.close();  
         }else {  
             OutputStream out = new FileOutputStream(f);  
             result = ftpClient.retrieveFile(remote, out);  
             out.close();  
         }  
         return result;  
     }  
       
     /** 
      * 上传文件到FTP服务器,支持断点续传 
      * @param local 本地文件名称,绝对路径 
      * @param remote 远程文件路径,使用/home/directory1/subdirectory/file.ext 按照Linux上的路径指定方式,支持多级目录嵌套,支持递归创建不存在的目录结构 
      * @return 上传结果 
      * @throws IOException 
      */  
     public UploadStatus upload(String local,String remote) throws IOException{  
         //设置PassiveMode传输  
         ftpClient.enterLocalPassiveMode();  
         //设置以二进制流的方式传输  
         ftpClient.setFileType(FTP.BINARY_FILE_TYPE);  
         UploadStatus result;  
         //对远程目录的处理  
         String remoteFileName = remote;  
         if(remote.contains("/")){  
             remoteFileName = remote.substring(remote.lastIndexOf("/")+1);  
             String directory = remote.substring(0,remote.lastIndexOf("/")+1);  
             if(!directory.equalsIgnoreCase("/")&&!ftpClient.changeWorkingDirectory(directory)){  
                 //如果远程目录不存在,则递归创建远程服务器目录  
                 int start=0;  
                 int end = 0;  
                 if(directory.startsWith("/")){  
                     start = 1;  
                 }else{  
                     start = 0;  
                 }  
                 end = directory.indexOf("/",start);  
                 while(true){  
                     String subDirectory = remote.substring(start,end);  
                     if(!ftpClient.changeWorkingDirectory(subDirectory)){  
                         if(ftpClient.makeDirectory(subDirectory)){  
                             ftpClient.changeWorkingDirectory(subDirectory);  
                         }else {  
                             System.out.println("创建目录失败");  
                             return UploadStatus.Create_Directory_Fail;  
                         }  
                     }  
                       
                     start = end + 1;  
                     end = directory.indexOf("/",start);  
                       
                     //检查所有目录是否创建完毕  
                     if(end <= start){  
                         break;  
                     }  
                 }  
             }  
         }  
           
         //检查远程是否存在文件  
         FTPFile[] files = ftpClient.listFiles(remoteFileName);  
         if(files.length == 1){  
             long remoteSize = files[0].getSize();  
             File f = new File(local);  
             long localSize = f.length();  
             if(remoteSize==localSize){  
                 return UploadStatus.File_Exits;  
             }else if(remoteSize > localSize){  
                 return UploadStatus.Remote_Bigger_Local;  
             }  
               
             //尝试移动文件内读取指针,实现断点续传  
             InputStream is = new FileInputStream(f);  
             if(is.skip(remoteSize)==remoteSize){  
             	// 设置断点续传的offset 其实很多中间件的存储都是存在偏移量  offset
                 **ftpClient.setRestartOffset(remoteSize);**  
                 if(ftpClient.storeFile(remote, is)){  
                     return UploadStatus.Upload_From_Break_Success;  
                 }  
             }  
               
             //如果断点续传没有成功,则删除服务器上文件,重新上传  
             if(!ftpClient.deleteFile(remoteFileName)){  
                 return UploadStatus.Delete_Remote_Faild;  
             }  
             is = new FileInputStream(f);  
             if(ftpClient.storeFile(remote, is)){      
                 result = UploadStatus.Upload_New_File_Success;  
             }else{  
                 result = UploadStatus.Upload_New_File_Failed;  
             }  
             is.close();  
         }else {  
             InputStream is = new FileInputStream(local);  
             if(ftpClient.storeFile(remoteFileName, is)){  
                 result = UploadStatus.Upload_New_File_Success;  
             }else{  
                 result = UploadStatus.Upload_New_File_Failed;  
             }  
             is.close();  
         }  
         return result;  
     }  
     /** 
      * 断开与远程服务器的连接 
      * @throws IOException 
      */  
     public void disconnect() throws IOException{  
         if(ftpClient.isConnected()){  
             ftpClient.disconnect();  
         }  
     }  
       
     public static void main(String[] args) {  
         ContinueFTP myFtp = new ContinueFTP();  
         try {  
             myFtp.connect("192.168.21.171", 21, "test", "test");  
             System.out.println(myFtp.upload("E:\\VP6.flv", "/MIS/video/VP6.flv"));  
             myFtp.disconnect();  
         } catch (IOException e) {  
             System.out.println("连接FTP出错:"+e.getMessage());  
         }  
     }  
 }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 中,我们可以使用 Apache Commons Net 库来实现 FTP 断点续传功能。具体实现步骤如下: 1. 创建 FTPClient 对象,并连接到 FTP 服务器: ```java FTPClient ftpClient = new FTPClient(); ftpClient.connect(server, port); ftpClient.login(user, password); ``` 2. 进入到 FTP 服务器上的需要上传或下载的目录: ```java ftpClient.changeWorkingDirectory(remoteDir); ``` 3. 在上传或下载文件前,记录上一次传输完成的位置: ```java long restartPosition = ftpClient.getRestartOffset(); ``` 4. 上传或下载文件时,指定 REST 命令参数即可实现断点续传: ```java // 上传文件 try (InputStream inputStream = new FileInputStream(localFile)) { ftpClient.setRestartOffset(restartPosition); ftpClient.storeFile(remoteFile, inputStream); } // 下载文件 try (OutputStream outputStream = new FileOutputStream(localFile, true)) { ftpClient.setRestartOffset(restartPosition); ftpClient.retrieveFile(remoteFile, outputStream); } ``` 需要注意的是,FTP 服务器可能不支持断点续传功能,因此在实现时需要判断服务器的支持情况。 完整的示例代码如下: ```java import java.io.*; import org.apache.commons.net.ftp.*; public class FtpResume { public static void main(String[] args) throws Exception { String server = "ftp.example.com"; int port = 21; String user = "username"; String password = "password"; String remoteDir = "/remote/dir/"; String remoteFile = "test.txt"; String localFile = "test.txt"; FTPClient ftpClient = new FTPClient(); ftpClient.connect(server, port); ftpClient.login(user, password); ftpClient.changeWorkingDirectory(remoteDir); long restartPosition = ftpClient.getRestartOffset(); // 上传文件 try (InputStream inputStream = new FileInputStream(localFile)) { ftpClient.setRestartOffset(restartPosition); ftpClient.storeFile(remoteFile, inputStream); } // 下载文件 try (OutputStream outputStream = new FileOutputStream(localFile, true)) { ftpClient.setRestartOffset(restartPosition); ftpClient.retrieveFile(remoteFile, outputStream); } ftpClient.disconnect(); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值