基于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 是否上传完毕

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值