ftp工具类

package com.coship.common.utils;

import java.io.BufferedInputStream;
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.UnsupportedEncodingException;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
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;

/**
* FTP工具类,使用Apache的FTP组件实现
*
 */
public class FtpUtil {

private static final Log log = Log.getLog(FtpUtil.class);
   public static final int BINARY_FILE_TYPE = FTP.BINARY_FILE_TYPE;
   public static final int ASCII_FILE_TYPE = FTP.ASCII_FILE_TYPE;
   public static final String ISO_8859_1 = "ISO-8859-1";
   
   public static final char FTP_PATH_CHAR = '/';


   /**
    *
    * 方法download的作用:FTP下载
    * 修改记录: [20120504_904032_增加存储路径]
    * @param ftpUrl 请求信息 格式:ftp://user:password@ip:port/path/fileName
    * @param storePath 文件存储路径
    * @param maxSize 文件大小,允许ftp下载远程文件的最大值,单位为byte,超过此大小将不允许下载
    * @return
    * @throws Exception
    * @Exception 异常对象
    * @version  1.0[修改时小数点后+1]
    */
   public static  File download(String ftpUrl,String storePath, long maxSize) throws Exception {

FtpConfInfo infoConf = getInfo(ftpUrl);
       
       if (infoConf == null) {
           log.error("构建FTP配置信息失败,请检查:" + ftpUrl);
           return null;
       }
       FTPClient client = null;
       File file = null;
       try {
           client=connectServer(infoConf);
           if (client == null) {
               log.error("构建FTP客户端失败");
               return null;
           }
           
           log.debug("FTP服务器连接成功");
           
           if (infoConf.getLocation() != null) {
               String[] ss = infoConf.getLocation().split("/");
               for (String s : ss) {
                   client.changeWorkingDirectory(s);
               }
           }
           log.debug("FTP切换目录成功download()");

String fileName = downFile(infoConf ,storePath==null?"":storePath, client, infoConf.getFileName(),
                   maxSize);

if (fileName == null) {
               return null;
           }
           file = new File(fileName);
           if (!file.isFile()) {
               log.error("下载的文件失败");
               return null;
           }
           log.debug("文件下载成功准备重命名,file = "+fileName);
           String suffix = infoConf.getFileName().substring(infoConf.getFileName().lastIndexOf('.'));
           File tempFile = new File(storePath+ File.separator +AssetIDUtil.getOnlyNumberForWebapp() + suffix);
           file.renameTo(tempFile);//重命名保持唯一性
           file = tempFile;
       } catch (Exception e) {
           log.error("", e);
           throw e;
       } finally {
           // 关闭ftp
           closeServer(client);
       }
       return file;
   }

/**
    * FTP批量下载文件到本地目录
    *
    * @param localPath
    *            本地目录
    * @param ftpUrlList
    *            FTP文件列表
    * @return localFilePathList 本地文件路径列表
    */
   public static List<String> downloadFiles(String localPath,
           List<String> ftpUrlList, long maxSize) throws Exception {
       List<String> localFilePathList = null;
       if (ftpUrlList != null && ftpUrlList.size() > 0) {
           localFilePathList = new ArrayList<String>();
           FtpConfInfo infoConf = getInfo(ftpUrlList.get(0));
           if (infoConf == null) {
               log.error("构建FTP配置信息失败,请检查:" + ftpUrlList.get(0));
               return null;
           }
           FTPClient client = null;
           try {
               client = connectServer(infoConf);
               if (client == null) {
                   log.error("构建FTP客户端失败");
                   return null;
               }
               for (String ftpUrl : ftpUrlList) {
                   infoConf = getInfo(ftpUrl);
                   if (infoConf.getLocation() != null) {
                       String[] ss = infoConf.getLocation().split("/");
                       for (String s : ss) {
                           client.changeWorkingDirectory(s);
                       }
                   }
                   String fileName = downFile(infoConf ,localPath + File.separator
                           + infoConf.getLocation(), client, infoConf
                           .getFileName(), maxSize);
                   if (fileName != null) {
                       localFilePathList.add(fileName);
                   }
               }
           } catch (Exception e) {
               log.error("", e);
               throw e;
           } finally {
               // 关闭ftp
               closeServer(client);
           }
       }
       return localFilePathList;
   }

/**
    * 判断是否有重名海报
    *
    * @param ftpUrl
    * @param newName
    * @return
    * @throws Exception
    */
   public static boolean checkName(String ftpUrl, String newName)
           throws Exception {
       FtpConfInfo infoConf = getInfo(ftpUrl);
       FTPClient ftpclient = null;
       if (infoConf.getLocation() != null) {
           ftpclient = connectServer(infoConf);
           String[] ss = infoConf.getLocation().split("/");
           for (String s : ss) {
               if (!existDirectory(ftpclient, s)) {
                   closeServer(ftpclient);
                   return true;
               }
               ftpclient.changeWorkingDirectory(s);
           }
       }
       if (ftpclient == null)
           throw new Exception("FTP链接不成功,请检查FTP链接参数!");
       if(newName==null)
           throw new Exception("检查重名方法的参数newName不允许为空!");
       else
           newName = new String(newName.getBytes(infoConf.getEncoding()),FtpUtil.ISO_8859_1);
       
       FTPFile[] files = listFiles(ftpclient, newName);
       closeServer(ftpclient);
       
       if (files.length > 0)
       {
           return false;
       }
       else
       {
           return true;
       }
   }

public static void clearPath(String ftpUrl, String newName)
           throws Exception {
       FtpConfInfo infoConf = getInfo(ftpUrl);
       FTPClient ftpclient = null;
       if (infoConf.getLocation() != null) {
           ftpclient = connectServer(infoConf);
           String[] ss = infoConf.getLocation().split("/");
           for (String s : ss) {
               if (!existDirectory(ftpclient, s)) {
                   closeServer(ftpclient);
                   return;
               }
               ftpclient.changeWorkingDirectory(s);
           }
       }
       if (ftpclient == null)
           throw new Exception("FTP链接不成功,请检查FTP链接参数!");
       if(newName==null)
           throw new Exception("删除文件方法的参数newName不允许为空!");
       else
           newName = new String(newName.getBytes(infoConf.getEncoding()),FtpUtil.ISO_8859_1);
       
       FTPFile[] files = listFiles(ftpclient, null);
       
       for (FTPFile file : files) {
           if (file.isFile()) {
               if (!file.getName().equals(newName))
                   ftpclient.deleteFile(file.getName());
           }
       }
       closeServer(ftpclient);
   }

/**
    * 上载文件到远程FTP路径中
    *
    * @param ftpUrl
    *            eg: ftp://admin:[email protected]:2121/poster/
    * @param file
    * @return [boolean] false=失败;true=成功.
    */
   public static boolean upload(String ftpUrl, File file, String newName)
           throws Exception {
       FtpConfInfo infoConf = getInfo(ftpUrl);
       if (infoConf == null) {
           log.error("构建FTP配置信息失败,请检查:" + ftpUrl);
           return false;
       }
       FTPClient ftpclient = connectServer(infoConf);
       if (ftpclient == null) {
           log.error("构建FTP客户端失败");
           return false;
       }
       if(newName==null)
           throw new Exception("上传文件方法的参数newName不允许为空!");
       else
           newName = new String(newName.getBytes(infoConf.getEncoding()),FtpUtil.ISO_8859_1);
       if (infoConf.getLocation() != null) {
           String[] ss = infoConf.getLocation().split("/");
           for (String s : ss) {
               if (!existDirectory(ftpclient, s))
                   ftpclient.mkd(s);
               ftpclient.changeWorkingDirectory(s);
           }
       }
       if (!file.exists()) {
           log.error("要上传的文件不存在");
           return false;
       }
       boolean storeResult = false;
       InputStream is = null;
       try {
           is = new FileInputStream(file);
           storeResult = ftpclient.storeFile(newName, is);
           if(!storeResult){
               ftpclient.enterLocalPassiveMode();
               storeResult = ftpclient.storeFile(newName, is);
           }
           log.debug("uploadFTP的当前目录" + ftpclient.printWorkingDirectory());
           ftpclient.logout();
           closeServer(ftpclient);
           if (storeResult)
               log.info("文件传输到FTP成功");
           else
               log.info("文件传输到FTP失败");
           return storeResult;
       } catch (Exception e) {
           log.error("", e);
           throw e;
       } finally {
           if (is != null)
               is.close();
       }
   }

/**
    * 删除FTP上的文件
    *
    * @param ftpUrl
    *            eg:ftp://admin:[email protected]:2121/IsmpPicture/201006/
    *            201006154100845_1083136_jpg
    * @return 删除海报失败
    * @throws Exception
    */
   public static boolean delete(String ftpUrl) throws Exception {
       boolean deleteResult = false;
       FtpConfInfo infoConf = getInfo(ftpUrl);
       if (infoConf == null) {
           log.error("构建FTP配置信息失败,请检查:" + ftpUrl);
           return false;
       }
       FTPClient ftpclient = connectServer(infoConf);
       if (ftpclient == null) {
           log.error("构建FTP客户端失败");
           return false;
       }
       if (infoConf.getFileName() != null) {
           if (infoConf.getLocation() != null) {
               deleteResult = ftpclient.deleteFile(infoConf.getLocation()
                       + "/" + infoConf.getFileName());
           } else {
               deleteResult = ftpclient.deleteFile(infoConf.getFileName());
           }
       }
       ftpclient.logout();
       closeServer(ftpclient);
       return deleteResult;
   }

/**
    * 获得FTP对象信息
    *
    * @param ftpInfo
    * @return FtpConfInfo
    */
   private static FtpConfInfo getInfo(String ftpInfo) {
       if (ftpInfo == null) {
           return null;
       }

String regEx = "^ftp://([\\w]+:[\\S]*@)?[\\S]+/[^\\/:*?\"<>|]*$";      
       Pattern p = Pattern.compile(regEx);
       Matcher m = p.matcher(ftpInfo);
       if (!m.find()) {
           return null;
       }

String str = ftpInfo.substring("ftp://".length());
       String serverInfo = str.substring(0, str.indexOf("/"));
       String fileName = str.substring(str.indexOf("/") + 1);
       // if path exist
       String path = null;
       if (fileName.indexOf("/") > -1) {
           path = fileName.substring(0, fileName.lastIndexOf("/"));
           fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
       }
       
       //解析ftp用户名、密码、IP、端口号 特别是密码含有特殊字符的如: "icdspics:ic:ds!@#@125.210.227.11:98"(lidahu)
       int k = serverInfo.indexOf(":");
       String serverName =serverInfo.substring(0,k) ;
       String server = serverInfo.substring(k+1);
       int j = server.lastIndexOf("@");
       String serverPwd = server.substring(0,j);
       
       String serverIpPort = server.substring(j+1);
       int i = serverIpPort.indexOf(":");
       String serverIp = null;
       String serverPort = null;
       if(i==-1){
           serverIp = serverIpPort;
       }
       else{
           serverIp =  serverIpPort.substring(0,i);
           serverPort= serverIpPort.substring(i+1);
       }
       FtpConfInfo conf = new FtpConfInfo();

conf.setUser(serverName);
       conf.setPassword(serverPwd);
       conf.setServer(serverIp);
       conf.setLocation(path);
       conf.setFileName(fileName);
       conf.setMaxWorkTime(60*1000l);//默认60秒完成
       if (StringUtils.isNotEmpty(serverPort)) {
           try {
               conf.setPort(Integer.parseInt(serverPort));
           } catch (ClassCastException e) {
               // 设置默认端口 21
               conf.setPort(21);
           }

} else {
           // 设置默认端口 21
           conf.setPort(21);
       }

return conf;

}
   
   
   /**
    * Check the path is exist; exist return true, else false.
    *
    * @param ftpClient
    * @param path
    * @return
    * @throws IOException
    */
   private static boolean existDirectory(FTPClient ftpClient, String path)
           throws IOException {        
       boolean flag = false;
       FTPFile[] listFiles;
       try {
           String Localpath = ftpClient.printWorkingDirectory();
           log.debug(Localpath);
           listFiles = listFiles(ftpClient, null);
       } catch (Exception e) {
           log.error("检查FTP路径发送错误",e);
           return false;
       }
       if(listFiles == null)return false;
       for(FTPFile ffile :listFiles){
           boolean isFile = ffile.isFile();
           if(!isFile){
               if(ffile.getName().equalsIgnoreCase(path)){
                   flag = true;
                   break;
               }
           }
       }
       return flag;
   }

/**
    * (私有方法)连接FTP,返回FTPClient连接[返回根目录],使用完连接后,调用closeServer关闭连接
    *
    * @param conf
    * @return FTPClient
    * @throws SocketException
    * @throws IOException
    */
   private static FTPClient connectServer(FtpConfInfo conf)
           throws SocketException, IOException {
       FTPClient ftpClient = new FTPClient();
       ftpClient.setConnectTimeout(5000);//超时设置,建议采用配置
       ftpClient.setDataTimeout(10*1000);//设置数据响应超时时间默认10秒

try {
           ftpClient.connect(conf.getServer(), conf.getPort());
       } catch (SocketException e ) {
           log.error("海报FTP服务器连接超时,请检查FTP服务器地址及端口配置是否正确:FTPServer[" + conf.getServer() + "]--Port[" + conf.getPort() + "]",e);
           throw e;
       }  catch (IOException e ) {
           log.error("海报FTP服务器连接超时,请检查FTP服务器地址及端口配置是否正确:FTPServer[" + conf.getServer() + "]--Port[" + conf.getPort() + "]",e);
           throw e;
       }

if (FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
           
           if (ftpClient.login(conf.getUser(), conf.getPassword())) {
               ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
               /** 解决中文问题的解码 903889 2010-12-30 Start **/
               ftpClient.sendCommand("FEAT");
               String featRS = ftpClient.getReplyString();
               String encoding = "GBK";
               if(featRS.indexOf(" UTF8")!=-1)encoding="UTF8";
               if(conf.getLocation()!=null)
                   conf.setLocation(new String(conf.getLocation().getBytes(encoding),FtpUtil.ISO_8859_1));
               if(conf.getFileName()!=null)
                   conf.setFileName(new String(conf.getFileName().getBytes(encoding),FtpUtil.ISO_8859_1));
               conf.setEncoding(encoding);//将获取的编码信息带出来
               
               ftpClient.setActivePortRange(9000, 9100);//主动模式下设置客户方端口范围9000-9100              
               
//              ftpClient.enterLocalPassiveMode();//将默认的PORT主动模式改成PASV被动模式
               /** 解决中文问题的解码 End **/
               return ftpClient;
           }
           closeServer(ftpClient);
           log.error("FTP的用户名和密码不对");
           log.error(conf.toString());
           return null;
       }
       closeServer(ftpClient);
       log.error("FTP的连接失败");
       log.error(conf.toString());
       return null;
   }

/**
    * (私有方法)关闭FTP连接
    *
    * @param ftpClient
    * @throws IOException
    */
   private static void closeServer(FTPClient ftpClient) throws IOException {
       if (ftpClient != null && ftpClient.isConnected()) {
           ftpClient.disconnect();
       }
   }
   
   /**
    * 取得ftp文件
    * @param ftp
    * @param fileName
    * @return
    * @throws IOException
    */
   private static FTPFile[] listFiles(FTPClient ftp, String fileName)
       throws IOException
   {
       FTPFile[] files = null;
       if (StringUtils.isNotEmpty(fileName))
       {
           files = ftp.listFiles(fileName);
           if (files.length != 1)
           {
               // 如果没有不能下载文件,再用被动模式试一次(lidahu)
               ftp.enterLocalPassiveMode();
               files = ftp.listFiles(fileName);
           }
       }
       else
       {
           files = ftp.listFiles();
           // 以被动模式再试一次
           if (files.length == 0 || files == null)
           {
               ftp.enterLocalPassiveMode();
               files = ftp.listFiles();
           }
       }
       return files;
   }

/**
    * (私有方法) 下载文件
    *
    * @param ftp
    * @param fileName
    * @param maxSize
    *            为-1不检查文件大小
    * @return String
    * @throws UnsupportedEncodingException
    * @throws IOException
    */
   private static String downFile(FtpConfInfo ftpConfInfo ,String path, FTPClient ftp, String fileName,
           long maxSize) throws UnsupportedEncodingException, IOException,
           Exception {
       if (ftp == null || fileName == null || fileName.length() < 1) {
           log.error("文件名为空或不存在");
           return null;
       }
       
       FTPFile[] files = listFiles(ftp,fileName);
       if(files.length != 1){
           log.error("PATH:" + path + "|FileName:" + fileName + "当前文件不存在或有多个,实际文件个数为:" + files.length);
           return null;
       }
       
       FTPFile file = files[0];
       if(!file.isFile()){
           log.error(file.getName() + "不是文件!");
           return null;
       }
       long lRemoteSize = file.getSize();
//      if (lRemoteSize > maxSize && maxSize != -1) {
//          log.error("要下载的文件太大,超过maxSize=" + maxSize + "chars");
//          return null;
//      }
       long maxTime = lRemoteSize/1024/50;//50K一秒,
       ftpConfInfo.setMaxWorkTime(maxTime*1000);
       
       if (path == null || path.equals("")) {
           String temp = System.getProperty("user.dir");
           path = temp;
       }
       File f = new File(path);
       if (!f.exists()) {
           boolean mkResult = f.mkdirs();
           if(!mkResult)log.warn("make dir failed");
       }
       path = path + File.separator + fileName;
       
       
       try
       {
           File localFile = new File(path);
           OutputStream output = new FileOutputStream(localFile);
           ftp.retrieveFile(fileName, output);
           output.close();
       }
       catch (Exception e)
       {
           log.error("下载文件"+path+"失败", e);
           throw new Exception("FTP传输失败,中断连接");
       }
       finally
       {
           FtpUtil.closeServer(ftp);
       }
       
       
       /*
       
       RFS rfs = new RFS(ftpConfInfo,ftp,path,fileName);
       rfs.setName("FtpRFS Thread");
       rfs.start();
       int forInt = 1;
       long oldfilesize = 0;      
       while(forInt < 20){
           Thread.sleep(200l);
           if(rfs.count >= lRemoteSize)break;//传输完毕,退出.兼容服务器的文件增大情况,不保证增大时完整性
           if(rfs.count == oldfilesize){   //相当的时候,增加计数器2秒,则开始中断          
               forInt++;              
           }  
           oldfilesize = rfs.count;//每次处理后,赋值供下次比较
       }

if(forInt == 20 ){ //存在FTP传输2秒无响应,中断连接
           log.error("FTP传输2秒无响应,中断连接");          
           rfs.myInterrupt();
           throw new Exception("FTP传输2秒无响应,中断连接");
       }
       log.debug(System.currentTimeMillis()+" "+rfs.toString()+ "="+rfs.getState().toString());
       if(rfs.getState()!=Thread.State.TERMINATED){//RFS还存活时,中断    
           Thread.sleep(100l);
           rfs.myInterrupt();
       }
       */
       
       return path;
   }
   
   public static String repairFtpString(String ftpString)
   {
       if(StringUtils.isNotEmpty(ftpString) && FTP_PATH_CHAR != ftpString.charAt(ftpString.length()-1))
       {
           return ftpString+FTP_PATH_CHAR;
       }
       else
       {
           return ftpString;
       }
   }

static class RFS extends Thread{
       private FTPClient ftp = null;
       volatile long count = 0;
       private String path = null;
       private String fileName = null;
       private FtpConfInfo ftpConfInfo =null;
       
       RFS(FtpConfInfo ftpConfInfo,FTPClient ftp,String path,String fileName){
           this.ftp = ftp;
           this.path = path;
           this.ftpConfInfo =ftpConfInfo;
           this.fileName = fileName;
       }
       
       public void myInterrupt() throws IOException{          
           Thread.currentThread().interrupt();        
           FtpUtil.closeServer(ftp);

}
       
       private void copy(FtpConfInfo ftpConfInfo ,InputStream is ,OutputStream os) throws IOException, Exception{
           long timeA = System.currentTimeMillis();
//          final StringBuffer timeout = new StringBuffer();
//          if (ftpConfInfo!=null&&ftpConfInfo.getMaxWorkTime() > 0) {
//              final Timer timer = new Timer();
//              timer.schedule(new TimerTask() {
//                  public void run() {
//                      timeout.append(true);
//                      timer.cancel();
//                  }
//              }, ftpConfInfo.getMaxWorkTime());
//          }
           byte[] buffer = new byte[1024];
           count = 0;
           int n = 0;
           while (-1 != (n = is.read(buffer))) {
//              if ("true".equals(timeout.toString())) {
//                  log.error("FTP数据传输时间超时!");
//                  throw new Exception("FTP数据传输时间超时!");
//              }
               os.write(buffer, 0, n);
               count += n;            
           }
           long copyTime = (System.currentTimeMillis()-timeA);
           if(copyTime<1){
               copyTime = 1;
           }
           log.debug("传输速率为(byte/毫秒):" + (count/copyTime)+"传输时间(毫秒)"+copyTime);    
       }
       
       public void run(){
           InputStream stO = null;
           OutputStream stD = null;
           try {          
               stO = new BufferedInputStream(ftp.retrieveFileStream(fileName));
               stD = new FileOutputStream(path);                
               log.debug("准备从FTP拷贝文件");
               copy(ftpConfInfo,stO,stD);
               stD.flush();
               log.debug("文件拷贝完成");
               ftp.completePendingCommand();
           } catch (Exception e) {
               log.error("文件传输异常", e);
           } finally {
               if (stO != null) {
                   try {
                       stO.close();
                   } catch (IOException e) {
                       log.error("FTP关闭输入流异常", e);
                   }
               }
               if (stD != null) {
                   try {
                       stD.flush();
                       stD.close();
                   } catch (IOException e) {                          
                       log.error("FTP关闭输出流异常", e);
                   }
                   
               }
               stO = null;
               stD = null;
           }
       }
   }

}


你可能感兴趣的:(ftp工具类)