Ftp Java工具類
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;
}
}
}
}</pre>