Ftp Java工具类
jopen
11年前
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:admin@172.30.20.121: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:admin@172.30.20.121: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; } } } }