JAVA实现FTP上传下载

来源:互联网 发布:网络小手翠微居 编辑:程序博客网 时间:2024/04/29 17:55

本代码需要 commons-net-3.1.jar 包的支持
官方网站  :  http://commons.apache.org/net/


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服务器 
      * @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){  
                 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());  
         }  

     }  

public enum UploadStatus {


CREATE_DIRECTORY_FAIL, // 远程服务器相应目录创建失败


CREATE_DIRECTORY_SUCCESS, // 远程服务器闯将目录成功


UPLOAD_NEW_FILE_SUCCESS, // 上传新文件成功


UPLOAD_NEW_FILE_FAILED, // 上传新文件失败


FILE_EXITS, // 文件已经存在


REMOTE_BIGGER_LOCAL, // 远程文件大于本地文件


UPLOAD_FROM_BREAK_SUCCESS, // 断点续传成功


UPLOAD_FROM_BREAK_FAILED, // 断点续传失败


DELETE_REMOTE_FAILD; // 删除远程文件失败


}

 }


/**ftp连接方式**/

主动 FTP :   命令连接:客户端 >1024 端口 -> 服务器 21 端口   数据连接:客户端 >1024 端口 <- 服务器 20 端口   

被动 FTP :   命令连接:客户端 >1024 端口 -> 服务器 21 端口   数据连接:客户端 >1024 端口 -> 服务器 >1024 端口 

FTP协议有两种工作方式:PORT方式和PASV方式,中文意思为主动式和被动式。     

PORT(主动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路。当需要传送数据时, 客户端在命令链路上用PORT命令告诉服务器:“我打开了***X端口,你过来连接我”。于是服务器从20端口向客户端的***X端口发送连接请求,建立 一条数据链路来传送数据。       

PASV(被动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路。当需要传送数据时, 服务器在命令链路上用PASV命令告诉客户端:“我打开了***X端口,你过来连接我”。于是客户端向服务器的***X端口发送连接请求,建立一条数据链 路来传送数据。


还有一种就是使用sun.net的包提供的方法,

sun.net.ftp.FtpClient类中函数的说明
sun.net.ftp.FtpClient.,该类库主要提供了用于建立FTP连接的类。利用这些类的方法,编程人员可以远程登录到FTP服务器,列举该服务器上的目录,设置传输协议,以及传送文件。FtpClient类涵盖了几乎所有FTP的功能,FtpClient的实例变量保存了有关建立"代理"的各种信息。下面给出了这些实例变量。
  public static boolean useFtpProxy
  这个变量用于表明FTP传输过程中是否使用了一个代理,因此,它实际上是一个标记,此标记若为TRUE,表明使用了一个代理主机。
  public static String ftpProxyHost
  此变量只有在变量useFtpProxy为TRUE时才有效,用于保存代理主机名。
  public static int ftpProxyPort
  此变量只有在变量useFtpProxy为TRUE时才有效,用于保存代理主机的端口地址。
  FtpClient有三种不同形式的构造函数,如下所示:
  1、public FtpClient(String hostname,int port)
   此构造函数利用给出的主机名和端口号建立一条FTP连接。
  2、public FtpClient(String hostname)
  此构造函数利用给出的主机名建立一条FTP连接,使用默认端口号。
  3、FtpClient()
  此构造函数将创建一FtpClient类,但不建立FTP连接。这时,FTP连接可以用openServer方法建立。
  一旦建立了类FtpClient,就可以用这个类的方法来打开与FTP服务器的连接。类ftpClient提供了如下两个可用于打开与FTP服务器之间的连接的方法。
  public void openServer(String hostname)
  这个方法用于建立一条与指定主机上的FTP服务器的连接,使用默认端口号。
  public void openServer(String host,int port)
  这个方法用于建立一条与指定主机、指定端口上的FTP服务器的连接。
  打开连接之后,接下来的工作是注册到FTP服务器。这时需要利用下面的方法。
  public void login(String username,String password)
  此方法利用参数username和password登录到FTP服务器。使用过Intemet的用户应该知道,匿名FTP服务器的登录用户名为anonymous,密码一般用自己的电子邮件地址。
  下面是FtpClient类所提供的一些控制命令。
  public void cd(String remoteDirectory)
  该命令用于把远程系统上的目录切换到参数remoteDirectory所指定的目录。
  public void cdUp():该命令用于把远程系统上的目录切换到上一级目录。
  public String pwd():该命令可显示远程系统上的目录状态。
  public void binary():该命令可把传输格式设置为二进制格式。
  public void ascii():该命令可把传输协议设置为ASCII码格式。
  public void rename(String string,String string1)
  该命令可对远程系统上的目录或者文件进行重命名操作。
  除了上述方法外,类FtpClient还提供了可用于传递并检索目录清单和文件的若干方法。这些方法返回的是可供读或写的输入、输出流。下面是其中一些主要的方法。
  public TelnetInputStream list()
  返回与远程机器上当前目录相对应的输入流。
  public TelnetInputStream get(String filename)
  获取远程机器上的文件filename,借助TelnetInputStream把该文件传送到本地。
  public TelnetOutputStream put(String filename)
  以写方式打开一输出流,通过这一输出流把文件filename传送到远程计算机。

以下是sun.net.ftp.FtpClient进行上传和下载的例子

import java.io.DataInputStream; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.FileInputStream; 
import java.util.ArrayList; 
import java.util.Date; 
import java.util.List; 
import sun.net.*; 
import sun.net.ftp.FtpClient;

/** 
     * connectServer 
     * 连接ftp服务器 
     * @throws java.io.IOException 
     * @param path 文件夹,空代表根目录 
     * @param password 密码 
     * @param user    登陆用户 
     * @param server 服务器地址 
     */ 
  public void connectServer(String server, String user, String password,  String path) 
  throws IOException 
   { 
     // server:FTP服务器的IP地址;user:登录FTP服务器的用户名 
     // password:登录FTP服务器的用户名的口令;path:FTP服务器上的路径 
      ftpClient = new FtpClient(); 
      ftpClient.openServer(server); 
      ftpClient.login(user, password); 
     //path是ftp服务下主目录的子目录 
     if (path.length() != 0)   ftpClient.cd(path); 
     //用2进制上传、下载 
      ftpClient.binary();      



/** 
     * upload 
     * 上传文件 
     * @throws java.lang.Exception 
     * @return -1 文件不存在 
     *           -2 文件内容为空 
     *           >0 成功上传,返回文件的大小 
     * @param newname 上传后的新文件名 
     * @param filename 上传的文件 
     */ 
public long upload(String filename,String newname) throws Exception 

     long result = 0; 
      TelnetOutputStream os = null; 
      FileInputStream is = null; 
     try {          
          java.io.File file_in = new java.io.File(filename); 
         if (!file_in.exists()) return -1; 
         if (file_in.length()==0) return -2; 
          os = ftpClient.put(newname); 
          result = file_in.length(); 
          is = new FileInputStream(file_in); 
         byte[] bytes = new byte[1024]; 
         int c; 
         while ((c = is.read(bytes)) != -1) { 
               os.write(bytes, 0, c); 
          } 
      } finally { 
         if (is != null) { 
              is.close(); 
          } 
         if (os != null) { 
             os.close(); 
          } 
      } 
    return result; 

/** 
     * upload 
     * @throws java.lang.Exception 
     * @return 
     * @param filename 
     */ 
public long upload(String filename) 
throws Exception 

    String newname = ""; 
    if (filename.indexOf("/")>-1) 
     { 
        newname = filename.substring(filename.lastIndexOf("/")+1); 
     }else 
     { 
        newname = filename; 
     } 
    return upload(filename,newname); 



/** 
     *   download 
     *   从ftp下载文件到本地 
     * @throws java.lang.Exception 
     * @return 
     * @param newfilename 本地生成的文件名 
     * @param filename 服务器上的文件名 
     */ 
public long download(String filename,String newfilename) 
throws Exception 
{   
    long result = 0; 
     TelnetInputStream is = null; 
     FileOutputStream os = null; 
    try 
     { 
        is = ftpClient.get(filename);        
        java.io.File outfile = new java.io.File(newfilename); 
        os = new FileOutputStream(outfile); 
       byte[] bytes = new byte[1024]; 
       int c; 
       while ((c = is.read(bytes)) != -1) { 
            os.write(bytes, 0, c); 
            result = result + c; 
        } 
     } catch (IOException e) 
     { 
        e.printStackTrace(); 
     } 
    finally { 
         if (is != null) { 
              is.close(); 
          } 
         if (os != null) { 
             os.close(); 
          } 
      } 
     return result; 

/** 
   * 取得某个目录下的所有文件列表 
   * 
   */ 
public List getFileList(String path) 

     List list = new ArrayList(); 
    try 
     { 
        DataInputStream dis = new   DataInputStream(ftpClient.nameList(path)); 
       String filename = ""; 
       while((filename=dis.readLine())!=null)   
        {   
          list.add(filename);         
        }   
    
     } catch (Exception e) 
     { 
        e.printStackTrace(); 
     } 
    return list; 



/** 
     * closeServer 
     * 断开与ftp服务器的链接 
     * @throws java.io.IOException 
     */ 
public void closeServer() 
throws IOException 
{    
   try 
    { 
      if (ftpClient != null) 
       { 
         ftpClient.closeServer();      
       } 
    } catch (IOException e) { 
       e.printStackTrace(); 
    } 

   
  public static void main(String [] args) throws Exception 
   { 
     FtpUtil ftp = new FtpUtil(); 
    try { 
         //连接ftp服务器 
          ftp.connectServer("10.163.7.15", "cxl", "1", "info2"); 
         /**   上传文件到 info2 文件夹下 */ 
          System.out.println("filesize:"+ftp.upload("f:/download/Install.exe")+"字节"); 
         /** 取得info2文件夹下的所有文件列表,并下载到 E盘下 */ 
          List list = ftp.getFileList("."); 
         for (int i=0;i<list.size();i++) 
          { 
            String filename = (String)list.get(i); 
             System.out.println(filename); 
             ftp.download(filename,"E:/"+filename); 
          } 
     } catch (Exception e) { 
       /// 
     }finally 
     { 
        ftp.closeServer(); 
     } 
   }   
}