基于applet的FTP断点上传组件(一)

公司项目上需要一个拖曳的组件,花了二周时间写了一个支持FTP和HTTP的上传组件,其中FTP支持断点续传

下面只介绍FTP的相关部分。

我们知道,FTP协议的底层协议是TCP协议,三次握手,可以建立持续的连接和服务器相互通信,和服务器建立相应的socket后,只需要发送相关的指令就可以了,

传输数据需要建立新的socket来和服务器通信。

applet客户端所做的事就是写相关的FTP客户端,然后与服务器通信。

先从FTPClient着手,写一个FTP客户端

 

  1. package ftpupload;
  2. import java.io.BufferedInputStream;
  3. import java.io.BufferedOutputStream;
  4. import java.io.DataOutputStream;
  5. import java.io.FileInputStream;
  6. import java.io.FileNotFoundException;
  7. import java.io.IOException;
  8. import java.io.OutputStream;
  9. import java.net.InetAddress;
  10. import java.net.SocketException;
  11. import java.net.UnknownHostException;
  12. /**
  13.  * 
  14.  * @author BruceXX
  15.  *
  16.  */
  17. public class FTPClient {
  18.     
  19.     
  20.     
  21.     private int ControlPort;
  22.     private String controlEncoding;
  23.     private boolean cancelTransfer;
  24.     private boolean detectTransferMode;
  25.     private long monitorInterval;
  26.     private int transferBufferSize;
  27.     private FTPControlSocket control;
  28.     private int timeout;
  29.     protected InetAddress remoteAddress;
  30.     private FTPReply lastReply;
  31.     protected FTPProcessListener listener;
  32.     private FTPDataSocket data;
  33.     private boolean isASCII;
  34.     
  35.     private long startSize;
  36.     private volatile boolean handling;
  37.     private volatile boolean over;
  38.     public FTPClient(){
  39.         
  40.         this.ControlPort=21;
  41.         this.controlEncoding="uTF-8";
  42.         this.cancelTransfer=false;
  43.         this.detectTransferMode=true;
  44.         this.monitorInterval=10*1024L;
  45.         this.transferBufferSize=16384;
  46.         this.handling=true;
  47.         this.over=false;
  48.     }
  49.     
  50.     /**
  51.      * 建立连接
  52.      * @throws FTPException
  53.      * @throws SocketException
  54.      * @throws IOException
  55.      */
  56.     
  57.     public void connect() throws FTPException, SocketException, IOException{
  58.         
  59.         checkConnection(false);
  60.         initalize(new FTPControlSocket(remoteAddress,ControlPort,timeout,controlEncoding));
  61.     }
  62.     
  63.     
  64.     /**
  65.      * 登陆
  66.      * @param user
  67.      * @param password
  68.      * @throws FTPException
  69.      * @throws IOException
  70.      */
  71.     public void login(String user,String password) throws FTPException, IOException{
  72.         
  73.         user(user);
  74.         pass(password);
  75.     }
  76.     
  77.     public void user(String user) throws FTPException, IOException{
  78.         
  79.         sendCommand("USER",user,"230,331");
  80.     }
  81.     
  82.     public void pass(String pass) throws FTPException, IOException{
  83.         
  84.         sendCommand("PASS",pass,"230,202,332");
  85.     }
  86.     
  87.     /**
  88.      * 进入某个目录
  89.      * @param dir
  90.      * @throws FTPException
  91.      * @throws IOException
  92.      */
  93.     
  94.     public void cd(String dir) throws FTPException, IOException{
  95.         
  96.         sendCommand("CWD",dir,"250");
  97.         
  98.     }
  99.     
  100.     /**
  101.      * 创建文件夹
  102.      * @param dir
  103.      * @throws FTPException
  104.      * @throws IOException
  105.      */
  106.     
  107.     public void mkdir(String dir) throws FTPException, IOException{
  108.         
  109.         sendCommand("MKD",dir,"200,250,257");
  110.     }
  111.     
  112.     /**
  113.      * 退出连接
  114.      * @throws FTPException
  115.      * @throws IOException
  116.      */
  117.     public void quit() throws FTPException, IOException{
  118.         sendCommand("QUIT"null"221,226");
  119.         
  120.     }
  121.     
  122.     /**
  123.      * 获取远程文件的大小
  124.      * @param remoteFile
  125.      * @return
  126.      * @throws FTPException
  127.      * @throws IOException
  128.      */
  129.     
  130.     public long getSize(String remoteFile) throws FTPException, IOException{
  131.         
  132.         checkConnection(true);
  133.         FTPReply replay=control.sendCommand("SIZE "+remoteFile);    
  134.         String replyText=replay.getReplyText();
  135.         int pos=replyText.indexOf(' ');
  136.         if(pos>0)
  137.             replyText=replyText.substring(0,pos);
  138.         try{
  139.         return Long.parseLong(replyText);
  140.         }catch(NumberFormatException e){
  141.             return 0L;
  142.         }
  143.     }
  144.     /**
  145.      * 设置文件传输的类型,FTP有两种,一种是BINARY,第二种是ASCII,我试验了一下,貌似binary可以传任何类型的,不像网上说的那些文本之类的需要用ASCII来传输
  146.      * @param type
  147.      * @throws FTPException
  148.      * @throws IOException
  149.      */
  150.     
  151.     private void sendTransferType(String type) throws FTPException, IOException{
  152.         
  153.         sendCommand("TYPE", type, "200");
  154.     }
  155.     
  156.     /**
  157.      * 根据文件名自动选择传输类型
  158.      * @param filename
  159.      * @throws FTPException
  160.      * @throws IOException
  161.      */
  162.     
  163.     public void autoChooseType(String filename) throws FTPException, IOException{
  164.         
  165.         if(detectTransferMode){
  166.             
  167.             if(FTPFileType.matchASCII(filename)){
  168.                 isASCII=true;
  169.                 sendTransferType("A");
  170.             }               
  171.             else{
  172.                 isASCII=false;
  173.                 sendTransferType("I");              
  174.             }
  175.         }
  176.     }
  177.     /**
  178.      * 来检验是否传输完毕
  179.      * @throws FTPException
  180.      * @throws IOException
  181.      */
  182.     
  183.     public void validateTransfer() throws FTPException, IOException{
  184.         
  185.         handling=true;
  186.         checkConnection(true);
  187.         String[] rightCode={"225""226""250""426""450"};
  188.         FTPReply reply=control.readReply();
  189.         String code=reply.getReplyCode();
  190.         if((code.equals("426") || code.equals("450")) && !cancelTransfer)
  191.         {
  192.             handling=false;
  193.             throw new FTPException(reply);
  194.         } else
  195.         {
  196.             
  197.             lastReply = control.validateReply(reply, rightCode);
  198.             handling=false;
  199.             return;
  200.         }
  201.        
  202.     }
  203.     /**
  204.      * 从某个断点开始续传
  205.      * @param startSize
  206.      * @throws FTPException
  207.      * @throws IOException
  208.      */
  209.     
  210.     public void restart(long startSize) throws FTPException, IOException{
  211.         
  212.         sendCommand("REST", startSize+"""350");
  213.     }
  214.     /**
  215.      * 向服务器传输文件
  216.      * @param remoteFile
  217.      * @throws FTPException
  218.      * @throws IOException
  219.      */
  220.     
  221.     public void storefile(String remoteFile) throws FTPException, IOException{
  222.         
  223.         sendCommand("STOR", remoteFile, "125,150,350");
  224.     }
  225.     /**
  226.      * 从服务器已有文件开始附加文件,续传可以用这个,也可以用STOR,不过STOR要先指定start后才可以
  227.      * @param remoteFile
  228.      * @throws FTPException
  229.      * @throws IOException
  230.      */
  231.     
  232.     public void appendfile(String remoteFile) throws FTPException, IOException{
  233.         
  234.         sendCommand("APPE", remoteFile, "125,150,350");
  235.     }
  236.     
  237.     /**
  238.      * 关闭文件传输流
  239.      */
  240.     private void closeSocket(){
  241.         
  242.         
  243.             try {
  244.                 if(data!=null){
  245.                 data.close();
  246.                 data=null;}
  247.             } catch (IOException e) {
  248.                 // TODO Auto-generated catch block
  249.                 e.printStackTrace();
  250.             }       
  251.     }
  252.     
  253.     /**
  254.      * 关闭文件传输流,以及相关的输出流
  255.      * @param out
  256.      */
  257.     
  258.     private void closeSocket(OutputStream out){
  259.         
  260.         
  261.             try {
  262.                 if(out!=null)
  263.                 out.close();
  264.             } catch (IOException e) {
  265.                 // TODO Auto-generated catch block
  266.                 e.printStackTrace();
  267.             }
  268.             closeSocket();
  269.     }
  270.     
  271.     /**
  272.      * 初始化传输条件,即传输之前的指令
  273.      * @param remoteFile
  274.      * @throws FTPException
  275.      */
  276.     
  277.     private void initTransfer(String remoteFile) throws FTPException{
  278.         
  279.         checkConnection(true);
  280.         cancelTransfer=false;
  281.         data=null;
  282.         try {
  283.             data=control.createDataSocketPASV();
  284.             data.setSoTimeOut(timeout);         
  285.             startSize=getStartSize(remoteFile);
  286.             if(!isASCII){               
  287.                 restart(startSize);
  288.                 storefile(remoteFile);
  289.             }
  290.             else{
  291.                 appendfile(remoteFile);
  292.             }
  293.             
  294.         } catch (Exception e) {
  295.             // TODO Auto-generated catch block
  296.             e.printStackTrace();
  297.         }
  298.         
  299.     }
  300.     
  301.     /**
  302.      * 传输文件整体过程
  303.      * @param localFile
  304.      * @param remoteFile
  305.      */
  306.     
  307.     public void transfer(String localFile,String remoteFile){
  308.         
  309.         
  310.         try {
  311.             Subtransfer(localFile, remoteFile);
  312.             over=true;
  313.             validateTransfer();
  314.         } catch (FTPException e) {
  315.             // TODO Auto-generated catch block
  316.             e.printStackTrace();
  317.         } catch (IOException e) {
  318.             // TODO Auto-generated catch block
  319.             e.printStackTrace();
  320.         }
  321.     }
  322.     
  323.     /**
  324.      * 传输文件写入过程
  325.      * @param localFile
  326.      * @param remoteFile
  327.      */
  328.     public void Subtransfer(String localFile,String remoteFile){
  329.         
  330.         BufferedInputStream bis=null;
  331.         BufferedOutputStream bos=null;
  332.         long size = 0L;
  333.         
  334.         try {
  335.             bis=new BufferedInputStream(new FileInputStream(localFile));
  336.             initTransfer(remoteFile);
  337.             bos=new BufferedOutputStream(new DataOutputStream(data.getOutputStream()),transferBufferSize*2);
  338. //          if(!isASCII)
  339.             bis.skip(startSize);
  340.             byte[] buffer=new byte[transferBufferSize];
  341.             byte prevBuf[] = null;
  342.             long monitorCount = 0L;
  343.             int count = 0;       
  344.             int separatorPos = 0;
  345.             byte[] linseparator=System.getProperty("line.separator").getBytes();
  346.             
  347.              while ((count = bis.read(buffer)) > 0 && !cancelTransfer) {
  348.                 if (isASCII) {
  349.                     for (int i = 0; i < count; i++) {
  350.                         boolean found = true;
  351.                         int skip = 0;
  352.                         for (; separatorPos < linseparator.length
  353.                                 && i + separatorPos < count; separatorPos++) {
  354.                             if (buffer[i + separatorPos] != linseparator[separatorPos]) {
  355.                                 found = false;
  356.                                 break;
  357.                             }
  358.                             skip++;
  359.                         }
  360.                         if (found) {
  361.                             if (separatorPos == linseparator.length) {
  362.                                 bos.write(13);
  363.                                 bos.write(10);
  364.                                 size += 2L;
  365.                                 monitorCount += 2L;
  366.                                 separatorPos = 0;
  367.                                 i += skip - 1;
  368.                                 prevBuf = null;
  369.                             } else {
  370.                                 prevBuf = new byte[skip];
  371.                                 for (int k = 0; k < skip; k++)
  372.                                     prevBuf[k] = buffer[i + k];
  373.                             }
  374.                         } else {
  375.                             if (prevBuf != null) {
  376.                                 bos.write(prevBuf);
  377.                                 size += prevBuf.length;
  378.                                 monitorCount += prevBuf.length;
  379.                                 prevBuf = null;
  380.                             }
  381.                             bos.write(buffer[i]);
  382.                             size++;
  383.                             monitorCount++;
  384.                             separatorPos = 0;
  385.                         }
  386.                     }
  387.                 } else {
  388.                     bos.write(buffer, 0, count);
  389.                     size += count;
  390.                     monitorCount += count;
  391.                 }
  392.                 if (prevBuf != null) {
  393.                     bos.write(prevBuf);
  394.                     size += prevBuf.length;
  395.                     monitorCount += prevBuf.length;
  396.                 }
  397.                 /**
  398.                  * 监听器转换数值,一定间隔内刷新数值
  399.                  */
  400.                 if (listener != null && monitorCount > monitorInterval) {
  401.                     listener.getUploadSize(size);
  402.                     monitorCount = 0L;
  403.                 }
  404.                 
  405.              }
  406.             
  407.         } catch (FileNotFoundException e) {
  408.             // TODO Auto-generated catch block
  409.             e.printStackTrace();
  410.         } catch (FTPException e) {
  411.             // TODO Auto-generated catch block
  412.             e.printStackTrace();
  413.         } catch (IOException e) {
  414.             // TODO Auto-generated catch block
  415.             e.printStackTrace();
  416.         }
  417.         finally{
  418.             
  419.                 try {
  420.                 if (bis != null)
  421.                     bis.close();
  422.             } catch (IOException e) {
  423.                 // TODO Auto-generated catch block
  424.                 e.printStackTrace();
  425.             }
  426.             closeSocket(bos);
  427.             if(listener!=null){
  428.                 listener.getUploadSize(size);
  429.             }
  430.         }
  431.     }
  432.     
  433.     
  434.     private void sendCommand(String command,String commandafter,String rightCodeSplit) throws FTPException, IOException{
  435.         checkConnection(true);
  436.         if(commandafter==null)
  437.             commandafter="";
  438.         String[] rightCode=rightCodeSplit.split(",");
  439.         FTPReply reply=control.sendCommand(command+" "+commandafter);
  440.         lastReply=control.validateReply(reply, rightCode);
  441.     }
  442.     
  443.     
  444.     /**
  445.      * 检验控制流
  446.      * @return
  447.      */
  448.     
  449.     public boolean connected(){
  450.         return control!=null;
  451.     }
  452.     
  453.     /**
  454.      * 检验连接
  455.      * @param shouldBeConnected
  456.      * @throws FTPException
  457.      */
  458.     
  459.     protected void checkConnection(boolean shouldBeConnected) throws FTPException{
  460.         
  461.         if(shouldBeConnected && !connected()){
  462.             
  463.             throw new FTPException("客户端还没有连上服务端");
  464.         }
  465.         if(!shouldBeConnected && connected()){
  466.             
  467.             throw new FTPException("客户端已经连上,请求的动作必须在建立连接之前进行");
  468.         }
  469.         else 
  470.             return;
  471.     }
  472.     
  473.     
  474.     protected void initalize(FTPControlSocket control) throws SocketException{
  475.         this.control=control;
  476.         control.setSoTimeOut(timeout);
  477.     }
  478.     
  479.     
  480.     public int getTimeout() {
  481.         return timeout;
  482.     }
  483.     public void setTimeout(int timeout) throws SocketException {
  484.         
  485.         this.timeout = timeout;
  486.         if(control!=null)
  487.             control.setSoTimeOut(timeout);
  488.     }
  489.     
  490.     public int getControlPort() {
  491.         return ControlPort;
  492.     }
  493.     public void setControlPort(int controlPort) {
  494.         ControlPort = controlPort;
  495.     }
  496.     public String getControlEncoding() {
  497.         return controlEncoding;
  498.     }
  499.     public void setControlEncoding(String controlEncoding) {
  500.         this.controlEncoding = controlEncoding;
  501.     }
  502.     public boolean isDetectTransferMode() {
  503.         return detectTransferMode;
  504.     }
  505.     public void setDetectTransferMode(boolean detectTransferMode) {
  506.         this.detectTransferMode = detectTransferMode;
  507.     }
  508.     public long getMonitorInterval() {
  509.         return monitorInterval;
  510.     }
  511.     public void setMonitorInterval(long monitorInterval) {
  512.         this.monitorInterval = monitorInterval;
  513.     }
  514.     public long getTransferBufferSize() {
  515.         return transferBufferSize;
  516.     }
  517.     public void setTransferBufferSize(int transferBufferSize) {
  518.         this.transferBufferSize = transferBufferSize;
  519.     }
  520.     public String getRemoteAddress() {
  521.         return remoteAddress.getHostName();
  522.     }
  523.     public void setRemoteAddress(InetAddress remoteAddress) {
  524.         this.remoteAddress = remoteAddress;
  525.     }
  526.     
  527.     public void setRemoteAddress(String remotehost){
  528.         try {
  529.             this.remoteAddress=InetAddress.getByName(remotehost);
  530.         } catch (UnknownHostException e) {
  531.             // TODO Auto-generated catch block
  532.             e.printStackTrace();
  533.         }
  534.     }
  535.     public FTPProcessListener getListener() {
  536.         return listener;
  537.     }
  538.     public void setListener(FTPProcessListener listener) {
  539.         this.listener = listener;
  540.     }
  541.     
  542.     /**
  543.      * 获取远程的文件大小,如果没有的话返回0
  544.      * @param remoteFile
  545.      * @return
  546.      * @throws FTPException
  547.      * @throws IOException
  548.      */
  549.     public long getStartSize(String remoteFile) throws FTPException, IOException {
  550.         if(startSize==0)            
  551.             return getSize(remoteFile);
  552.         else
  553.             return startSize;
  554.     }
  555.     
  556.     public static void main(String args[]){
  557.         
  558.         Thread temp=null;
  559.         String remoteFolder="";
  560.         FTPClient client=new FTPClient();
  561.         client.setRemoteAddress("localhost");
  562.         try {
  563.             client.setTimeout(10000);
  564.             client.connect();
  565.             client.login("BruceXX""183320433");
  566.             client.cd(" /");
  567.             if(!remoteFolder.equals("")){
  568.                 String[] t=remoteFolder.split("/");
  569.                 StringBuffer sb=new StringBuffer();
  570.                 for(int i=0;i<t.length;i++){
  571.                     sb.append(t[i]+"/");
  572.                     client.mkdir(sb.toString());
  573.                 }
  574.                 client.cd(remoteFolder);
  575.             }
  576.             final long size=client.getStartSize("ttplayer.exe");
  577.             final FTPProcessMointor m=new FTPProcessMointor();
  578.             client.setListener(m);
  579.             client.autoChooseType("ttplayer.exe");
  580.             temp=new Thread(new Runnable(){
  581.                 
  582.                 public void run() {
  583.                     // TODO Auto-generated method stub
  584.                     while(true){
  585. //                      System.out.println(monitor.uploadSize);
  586.                         System.out.println("现文件大小:"+(m.uploadSize+size));
  587.                         try {
  588.                             Thread.sleep(1000);
  589.                         } catch (InterruptedException e) {
  590.                             // TODO Auto-generated catch block
  591.                             e.printStackTrace();
  592.                         }
  593.                     }
  594.                     
  595.                 }
  596.                 
  597.             });
  598.             temp.start();
  599.             client.transfer("F://ttplayer.exe""ttplayer.exe");
  600.             
  601.             
  602.             
  603.             
  604.             
  605.         } catch (SocketException e) {
  606.             // TODO Auto-generated catch block
  607.             e.printStackTrace();
  608.         } catch (FTPException e) {
  609.             // TODO Auto-generated catch block
  610.             e.printStackTrace();
  611.         } catch (IOException e) {
  612.             // TODO Auto-generated catch block
  613.             e.printStackTrace();
  614.         }
  615.         
  616.     }
  617.     public void setCancelTransfer(boolean cancelTransfer) {
  618.         this.cancelTransfer = cancelTransfer;
  619.     }
  620.     public boolean isHandling() {
  621.         return handling;
  622.     }
  623.     public boolean isOver() {
  624.         return over;
  625.     }
  626.     
  627.     
  628.     
  629. }

 

detectTransferMode  用来是否自动检测文件传输类型

monitorInterval 

里面用到了FTPProcessListener 这个监听上传进度的接口,

monitorInterval 是用来设定隔多少个长度刷新一次正在上传的大小

transferBufferSize 传输缓存大小

FTPControlSocket control 主要用来发送指定的socket

timeout 设定socket的超时时间

FTPReply lastReply 用来获取最后的响应时间

FTPDataSocket data 传输socket

isASCII 文件传输类型

handling 是否上传完了正在等待服务器接收完毕

over 是否上传完毕

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值