java實現FTP上傳(檔案)、下載(檔案、資料夾、資料夾遞迴)、刪除(檔案、資料夾遞迴)
提示:必須先保證有在FTP上上傳、下載、刪除的許可權!
本文結構 ---- 先給出測試樣例(圖片版),再給出工具類程式碼(文字版)!
上傳測試
注意:.uploadFile(String remoteDir, String remoteFileName, File file)中,remoteDir統一寫(以“/”分割的)絕對路徑; remoteDir可以是不存在的目錄(會自動建立);更多詳情見程式碼註釋!
執行主函式:可看到上傳成功(ie瀏覽器開啟ftp://10.2.6.16:22/test/):
多次上傳,得到現有目錄(ie瀏覽器開啟ftp://10.2.6.16:22/test/):
可以看見:/test/下有a、b、c這三個目錄(每個目錄下都有各自的檔案);還有SQL語句.txt、 justry_deng.html、JustryDeng.shuaige這三個檔案了。
由此可見:上傳成功!
單檔案下載測試
注:.downloadFile(String remoteDirOrRemoteFile, String localDir)中,remoteDirOrRemoteFile統一 寫(以“/”分割的)絕對路徑;localDir可以是不存在的目錄(會自動建立);更多詳情見程式碼註釋!
注:如果remoteDirOrRemoteFile
執行主函式,可看到下載成功:
注:下載下來的檔案的內容也是正確無亂碼的。
注:.recursiveDownloadFile(String remoteDirOrRemoteFile, String localDir)方法也支援單檔案下載。
由此可見:檔案下載成功!
指定目錄下所有檔案下載(不包括:下載該目錄下的資料夾及其內部內容)測試
注:.downloadFile(String remoteDirOrRemoteFile, String localDir)中,remoteDirOrRemoteFile統一
寫(以“/”分割的)絕對路徑
執行主函式,可看到下載成功:
注:可以看到,不僅把FTP 的/test/目錄下的檔案下載下來了,並沒有下載/test/目錄下的a、b、c資料夾。
由此可見:指定目錄下所有檔案下載成功!
指定目錄下所有檔案下載(還包括:下載該目錄下的資料夾及其內部內容)測試
注:.recursiveDownloadFile(String remoteDirOrRemoteFile, String localDir)中,remoteDirOrRemoteFile統一 寫(以“/”分割的)絕對路徑;localDir可以是不存在的目錄(會自動建立);更多詳情見程式碼註釋!
執行主函式,可看到下載成功:
注:可以看到,不僅把FTP 的/test/目錄下的有SQL語句.txt、justry_deng.html、JustryDeng.shuaige這三個檔案 下載下來了,還把/test/目錄下的a、b、c資料夾(以及每個資料夾裡面的檔案、子資料夾)都下載下來了。
由此可見:指定目錄下所有檔案、資料夾(遞迴)下載成功!
單檔案刪除測試
注:.deleteBlankDirOrFile(String deletedBlankDirOrFile)中,deletedBlankDirOrFile統一寫(以“/”分割的)絕對路徑, 可以是一個明確的要刪除的檔案全路徑;也可以是一個空的資料夾路徑;更多詳情見程式碼註釋!
執行主函式,可看到下載成功(ie瀏覽器開啟ftp://10.2.6.16:22/):
注:可以看到,FTP 的/test/目錄下的JustryDeng.shuaige檔案已經被刪除了。
由此可見:單檔案刪除成功!
指定目錄刪除(包括:刪除該目錄下的資料夾及其內部內容)測試
刪除前,FTP是有/test/目錄的,且其內容為:
呼叫FTP工具類刪除:
執行主函式後,ie瀏覽器開啟ftp://10.2.6.16:22/,可以看見:
FTP目錄下找不到test目錄了,即:刪除test資料夾(即裡面的內容)成功!
由此可見:資料夾(含不含內容都可以)刪除成功!
>>> 進入正題
本人測試時,軟硬體環境: JDK1.8、Windows、Eclipse、SpringBoot、FTP伺服器(windows下的)
準備工作:在pom.xml中引入依賴
<!--
Apache Commons Net library contains a collection of network utilities
and protocol implementations. Supported protocols include: Echo, Finger,
FTP, NNTP, NTP, POP3(S), SMTP(S), Telnet, Whois
-->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.6</version>
</dependency>
FTP工具類
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.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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上傳、下載、刪除 工具類
* 約定:統一使用絕對路徑
*
* @author JustryDeng
* @DATE 2018年9月26日 上午10:38:46
*/
public class FTPUtils {
/** ftp伺服器地址 */
private String hostname;
/** 埠號 */
private Integer port;
/** ftp登入賬號 */
private String username;
/** ftp登入密碼 */
private String password;
/**
* 命令 語句 編碼(控制發出去的命令的編碼)
* 如:在刪除時,明明提示刪除成功了,但是FTP上的檔案依然存在
* 這很可能就是因為:發出去的指令由於此處的編碼的源因,亂碼了;導
* 致刪除了一個不存在的檔案,所以返回的提示為成功,
* 但是FTP上的要刪除的檔案依然存在
*
* 注:根據不同的(Server/Client)情況,這裡靈活設定
*/
private String sendCommandStringEncoding = "ISO-8859-1";
/**
* 下載檔案,檔名encode編碼
*
* 注:根據不同的(Server/Client)情況,這裡靈活設定
*/
private String downfileNameEncodingParam1 = "ISO-8859-1";
/**
* 下載檔案,檔名decode編碼
*
* 注:根據不同的(Server/Client)情況,這裡靈活設定
*/
private String downfileNameDecodingParam2 = "GBK";
/**
* 設定檔案傳輸形式(使用FTP類靜態常量賦值即可)
*
* 注:根據要下載上傳的檔案情況,這裡靈活設定
*/
private Integer transportFileType = FTP.BINARY_FILE_TYPE;
/** FTP客戶端引用 */
private FTPClient ftpClient = null;
public FTPClient getFtpClient() {
return ftpClient;
}
private FTPUtils(String hostname, Integer port, String username, String password) {
super();
this.hostname = hostname;
this.port = port;
this.username = username;
this.password = password;
}
/**
* 設定下載時,檔名的編碼
* 即:new String(file.getName().getBytes(param1), param2) 中的param1
* 注:根據不同的(Server/Client)情況,這裡靈活設定
*
* @DATE 2018年9月26日 下午7:34:26
*/
public void setDownfileNameEncodingParam1(String downfileNameEncodingParam1) {
this.downfileNameEncodingParam1 = downfileNameEncodingParam1;
}
/**
* 設定下載時,檔名的編碼
* 即:new String(file.getName().getBytes(param1), param2) 中的param2
* 注:根據不同的(Server/Client)情況,這裡靈活設定
*
* @DATE 2018年9月26日 下午7:34:26
*/
public void setDownfileNameDecodingParam2(String downfileNameDecodingParam2) {
this.downfileNameDecodingParam2 = downfileNameDecodingParam2;
}
/**
* 設定檔案傳輸形式 -> 二進位制
* 根據自己的時機情況,選擇FTP.BINARY_FILE_TYPE或FTP.ASCII_FILE_TYPE等即可
* 注:根據不同的檔案情況,這裡靈活設定
*
* @DATE 2018年9月27日 上午9:48:51
*/
public void setTransportFileType(Integer transportFileType) {
if( transportFileType != null) {
this.transportFileType = transportFileType;
}
}
/**
* @param hostname
* FTPServer ip
* @param port
* FTPServer 埠
* @return FTPUtils例項
* @DATE 2018年9月26日 下午4:35:40
*/
public static FTPUtils getFTPUtilsInstance(String hostname, Integer port) {
return getFTPUtilsInstance(hostname, port, null, null);
}
/**
* FTP的上傳、下載、刪除,底層還是 傳送得命令語句; 這裡就設定傳送的命令語句的編碼
*
* Saves the character encoding to be used by the FTP control connection.
* Some FTP servers require that commands be issued in a non-ASCII
* encoding like UTF-8 so that filenames with multi-byte character
* representations (e.g, Big 8) can be specified.
*/
public void setSendCommandStringEncoding(String sendCommandStringEncoding) {
this.sendCommandStringEncoding = sendCommandStringEncoding;
}
/**
* @param hostname
* FTPServer ip
* @param port
* FTPServer 埠
* @param username
* 使用者名稱
* @param password
* 密碼
* @return FTPUtils例項
* @DATE 2018年9月26日 下午4:39:02
*/
public static FTPUtils getFTPUtilsInstance(String hostname, Integer port, String username, String password) {
return new FTPUtils(hostname, port, username, password);
}
/**
* 初始化FTP伺服器
* 注:連線FTP伺服器後,當前目錄(即:session)預設處於根目錄“/”下;
* 所以如果一開始就是相對路徑的話,那麼是相對根目錄的
*
* @throws IOException
* @DATE 2018年9月26日 下午1:37:14
*/
private void initFtpClient() throws IOException {
ftpClient = new FTPClient();
ftpClient.setControlEncoding(sendCommandStringEncoding);
System.out.println(" FTPUtils -> connecting FTPServer -> " + this.hostname + ":" + this.port);
// 連線ftp伺服器
ftpClient.connect(hostname, port);
if(username != null && password != null) {
//登入ftp伺服器
ftpClient.login(username, password);
}
// 設定檔案傳輸形式
ftpClient.setFileType(transportFileType);
// Returns the integer value of the reply code of the last FTP reply.
int replyCode = ftpClient.getReplyCode();
// Determine if a reply code is a positive completion response.
if(FTPReply.isPositiveCompletion(replyCode)){
System.out.println(" FTPUtils -> connect FTPServer success!");
} else {
System.err.println(" FTPUtils -> connect FTPServer fail!");
}
}
/**
* 上傳檔案至FTP
* 注:若有同名檔案,那麼原檔案會被覆蓋
*
* @param remoteDir
* 上傳到指定目錄(絕對路徑) 如果寫的相對路徑,那麼會預設在其前面加一個"/"
* 統一:路徑分割符 用“/”,而不用“\”;
*
* @param remoteFileName
* 上傳到FTP,該檔案的檔名
* @param file
* 要上傳的本地檔案
* @return 上傳結果
* @throws IOException
* @DATE 2018年9月26日 下午1:35:27
*/
public boolean uploadFile(String remoteDir, String remoteFileName, File file) throws IOException{
boolean result = false;
InputStream inputStream = null;
try{
inputStream = new FileInputStream(file);
// 初始化
initFtpClient();
CreateDirecroty(remoteDir);
ftpClient.makeDirectory(remoteDir);
ftpClient.changeWorkingDirectory(remoteDir);
result = ftpClient.storeFile(remoteFileName, inputStream);
}finally{
// 先登出、再關閉連線
ftpClient.logout();
if(ftpClient.isConnected()){
ftpClient.disconnect();
}
if(null != inputStream){
inputStream.close();
}
}
System.out.println(" FTPUtils -> uploadFile boolean result is ---> " + result);
return result;
}
/**
* 從FTP下載檔案
* 注:如果remoteDirOrRemoteFile不存在,再不會下載下來任何東西
*
* @param remoteDirOrRemoteFile
* FTP中的某一個目錄(此時下載該目錄下的所有檔案,該目錄下的資料夾不會被下載);
* 或 FTP中的某一個檔案全路徑名(此時下載該檔案)
* 統一:路徑分割符 用“/”,而不用“\”;
*
* @param localDir
* 本地用於儲存下載下來的檔案的資料夾
* 統一:路徑分割符 用“/”,而不用“\”;
* @return 下載了的檔案個數
* @throws IOException
* @DATE 2018年9月26日 下午7:24:11
*/
public int downloadFile(String remoteDirOrRemoteFile, String localDir) throws IOException{
//如果資料夾不存在則建立
File localfile = new File(localDir);
if (!localfile.exists()) {
System.out.println(" " + localDir + "is not exist, create this Dir!");
localfile.mkdir();
}
int successSum = 0;
int failSum = 0;
OutputStream os=null;
try {
initFtpClient();
// 根據remoteDirOrRemoteFile是檔案還是目錄,來切換changeWorkingDirectory
if(remoteDirOrRemoteFile.lastIndexOf(".") < 0) {
// 切換至要下載的檔案所在的目錄,否者下載下來的檔案大小為0
ftpClient.changeWorkingDirectory(remoteDirOrRemoteFile);
}else {
String tempWorkingDirectory = "";
int index = remoteDirOrRemoteFile.lastIndexOf("/");
if (index > 0) {
tempWorkingDirectory = remoteDirOrRemoteFile.substring(0, index);
}else {
tempWorkingDirectory = "/";
}
// 切換至要下載的檔案所在的目錄,否者下載下來的檔案大小為0
ftpClient.changeWorkingDirectory(tempWorkingDirectory);
}
// 獲取remoteDirOrRemoteFile目錄下所有 檔案以及資料夾 或 獲取指定的檔案
FTPFile[] ftpFiles = ftpClient.listFiles(remoteDirOrRemoteFile);
for(FTPFile file : ftpFiles){
// 如果是資料夾,那麼不下載 (因為:直接下載資料夾的話,是無效檔案)
if(file.isDirectory()) {
continue;
}
String name = new String(file.getName().getBytes(this.downfileNameEncodingParam1),
this.downfileNameDecodingParam2);
File localFile = new File(localDir + "/" + name);
os = new FileOutputStream(localFile);
boolean result = ftpClient.retrieveFile(file.getName(), os);
if (result) {
successSum++;
} else {
failSum++;
}
System.out.println(" already success download item count ---> " + successSum);
}
} finally{
// 先登出、再關閉連線
ftpClient.logout();
if(ftpClient.isConnected()){
ftpClient.disconnect();
}
if(os != null){
os.close();
}
}
System.out.println(" FTPUtils -> downloadFile success download file total ---> " + successSum);
System.out.println(" FTPUtils -> downloadFile fail download file total ---> " + failSum);
return successSum;
}
/**
* downloadFile的升級版 -> 其功能如下:
* 1.remoteDirOrRemoteFile可為FTP上某一個檔案的全路徑名
* ---> 下載該檔案,此處與downloadFile功能一致
*
* 2.remoteDirOrRemoteFile可為FTP上某一個檔案目錄名
* ---> 下載該目錄下的所有檔案、資料夾(包括該資料夾中的所有檔案資料夾並以此類推)
* 注:對比downloadFile方法可知,downloadFile只能下載該目錄下的所有檔案,不能遞迴下載
*
* @DATE 2018年9月26日 下午7:26:22
*/
public int recursiveDownloadFile(String remoteDirOrRemoteFile, String localDir) throws IOException{
int successSum = 0;
// remoteDirOrRemoteFile是一個明確的檔案 還是 一個目錄
if(remoteDirOrRemoteFile.indexOf(".") >= 0) {
successSum = downloadFile(remoteDirOrRemoteFile, localDir);
}else {
/// 初步組裝資料,呼叫遞迴方法;查詢給定FTP目錄以及其所有子孫目錄,進而得到FTP目錄與本地目錄的對應關係Map
// 有序存放FTP remote資料夾路徑
// 其實邏輯是:先往alreadyQueriedDirList裡面存,再進行的查詢。此處可以這麼處理。
List<String> alreadyQueryDirList = new ArrayList<>(16);
alreadyQueryDirList.add(remoteDirOrRemoteFile);
// 有序存放FTP remote資料夾路徑
List<String> requiredQueryDirList = new ArrayList<>(16);
requiredQueryDirList.add(remoteDirOrRemoteFile);
// 記錄FTP目錄與 本地目錄對應關係
Map<String, String> storeDataMap = new HashMap<>();
storeDataMap.put(remoteDirOrRemoteFile, localDir);
queryFTPAllChildrenDirectory(storeDataMap, alreadyQueryDirList, requiredQueryDirList);
// 迴圈呼叫downloadFile()方法,進行巢狀下載
for (int i = 0; i < alreadyQueryDirList.size(); i++) {
int thiscount = downloadFile(alreadyQueryDirList.get(i),
storeDataMap.get(alreadyQueryDirList.get(i)));
successSum += thiscount;
}
}
System.out.println(" FTPUtils -> recursiveDownloadFile(excluded created directories) "
+ " success download file total ---> " + successSum);
return successSum;
}
/**
* 刪除檔案 或 刪除空的資料夾
*
* @param deletedDirOrFile
* 要刪除的檔案的全路徑名 或 要刪除的空資料夾全路徑名
* 統一:路徑分割符 用“/”,而不用“\”;
*
* @return 刪除成功與否
* @throws IOException
* @DATE 2018年9月26日 下午9:12:07
*/
public boolean deleteBlankDirOrFile(String deletedBlankDirOrFile) throws IOException{
boolean flag = false;
try {
initFtpClient();
// 根據remoteDirOrRemoteFile是檔案還是目錄,來切換changeWorkingDirectory
if(deletedBlankDirOrFile.lastIndexOf(".") < 0) {
// 出於保護機制:如果當前資料夾中是空的,那麼才能刪除成功
flag = ftpClient.removeDirectory(deletedBlankDirOrFile);
// 不排除哪些 沒有後綴名的檔案 存在的可能;
// 如果刪除空資料夾失敗,那麼其可能是沒有後綴名的檔案,那麼嘗試著刪除檔案
if (!flag) {
flag = ftpClient.deleteFile(deletedBlankDirOrFile);
}
}else {/// 如果是檔案,那麼直接刪除該檔案
String tempWorkingDirectory = "";
int index = deletedBlankDirOrFile.lastIndexOf("/");
if (index > 0) {
tempWorkingDirectory = deletedBlankDirOrFile.substring(0, index);
}else {
tempWorkingDirectory = "/";
}
// 切換至要下載的檔案所在的目錄,否者下載下來的檔案大小為0
ftpClient.changeWorkingDirectory(tempWorkingDirectory);
flag = ftpClient.deleteFile(deletedBlankDirOrFile.substring(index + 1));
}
} finally {
ftpClient.logout();
if(ftpClient.isConnected()){
ftpClient.disconnect();
}
}
if (flag == false) {
System.out.println(" FTPUtils -> deleteBlankDirOrFile Maybe [" + deletedBlankDirOrFile
+ "] doesn't exist !");
}
System.out.println(" FTPUtils -> deleteBlankDirOrFile [" + deletedBlankDirOrFile
+ "] boolean result is ---> " + flag);
return flag;
}
/**
* deleteBlankDirOrFile的加強版 -> 可刪除檔案、空資料夾、非空資料夾
*
* @param deletedBlankDirOrFile
* @return
* @throws IOException
* @DATE 2018年9月27日 上午1:25:16
*/
public boolean recursiveDeleteBlankDirOrFile(String deletedBlankDirOrFile) throws IOException{
boolean result = true;
if(!destDirExist(deletedBlankDirOrFile)) {
System.out.println(" " + deletedBlankDirOrFile + " maybe is a non-suffix file!, try delete!");
boolean flag = deleteBlankDirOrFile(deletedBlankDirOrFile);
String flagIsTrue = " FTPUtils -> recursiveDeleteBlankDirOrFile "
+ deletedBlankDirOrFile + "---> success!";
String flagIsFalse = " FTPUtils -> recursiveDeleteBlankDirOrFile "
+ deletedBlankDirOrFile + "---> target file is not exist!";
System.out.println(flag == true ? flagIsTrue : flagIsFalse);
return true;
}
// remoteDirOrRemoteFile是一個明確的檔案 還是 一個目錄
if (deletedBlankDirOrFile.indexOf(".") >= 0 || !ftputilsChangeWorkingDirectory(deletedBlankDirOrFile)) {
result = deleteBlankDirOrFile(deletedBlankDirOrFile);
} else {
/// 初步組裝資料,呼叫遞迴方法;查詢給定FTP目錄以及其所有子孫目錄、子孫檔案 (含其自身)
// 存放 資料夾路徑
// 其實邏輯是:先往alreadyQueriedDirList裡面存,再進行的查詢。此處可以這麼處理。
List<String> alreadyQueriedDirList = new ArrayList<>(16);
alreadyQueriedDirList.add(deletedBlankDirOrFile);
// 存放 檔案路徑
List<String> alreadyQueriedFileList = new ArrayList<>(16);
// 存放 資料夾路徑
List<String> requiredQueryDirList = new ArrayList<>(16);
requiredQueryDirList.add(deletedBlankDirOrFile);
queryAllChildrenDirAndChildrenFile(alreadyQueriedDirList,
alreadyQueriedFileList,
requiredQueryDirList);
// 迴圈呼叫deleteBlankDirOrFile()方法,刪除檔案
for (int i = 0; i < alreadyQueriedFileList.size(); i++) {
boolean isSuccess = deleteBlankDirOrFile(alreadyQueriedFileList.get(i));
if (!isSuccess) {
result = false;
}
}
// 對alreadyQueriedDirList進行排序,以保證等下刪除時,先刪除的空資料夾是 最下面的
String[] alreadyQueriedDirArray = new String[alreadyQueriedDirList.size()];
alreadyQueriedDirArray = alreadyQueriedDirList.toArray(alreadyQueriedDirArray);
sortArray(alreadyQueriedDirArray);
// 迴圈呼叫deleteBlankDirOrFile()方法,刪除空的資料夾
for (int i = 0; i < alreadyQueriedDirArray.length; i++) {
boolean isSuccess = deleteBlankDirOrFile(alreadyQueriedDirArray[i]);
if (!isSuccess) {
result = false;
}
}
}
System.out.println(" FTPUtils -> recursiveDeleteBlankDirOrFile "
+ " boolean result is---> " + result);
return result;
}
/* -------------JustryDeng-------------以下為輔助方法-------------JustryDeng------------- */
/**
* 根據陣列元素的長度,來進行排序(字串長的,排在前面)
* 陣列元素不能為null
*
* @DATE 2018年9月27日 上午12:54:03
*/
private void sortArray(String[] array) {
for (int i = 0; i < array.length - 1; i++) {
for(int j = 0; j < array.length - 1 - i; j++) {
if (array[j].length() - array[j+1].length() < 0) {
String flag=array[j];
array[j] = array[j+1];
array[j+1] = flag;
}
}
}
}
/**
* 根據給出的FTP目錄、對應本地目錄; 查詢該FTP目錄的所有子目錄 , 以及獲得與每一個子目錄對應的本地目錄(含其自身以及與其自身對應的本地目錄)
*
* @param storeDataMap
* 儲存FTP目錄與本地目錄的對應關係;key -> FTP目錄, value -> 與key對應的本地目錄
* @param alreadyQueryDirList
* 所有已經查詢過了的FTP目錄,即:key集合
* @param requiredQueryDirList
* 還需要查詢的FTP目錄
* @throws IOException
* @DATE 2018年9月26日 下午7:17:52
*/
private void queryFTPAllChildrenDirectory(Map<String, String> storeDataMap,
List<String> alreadyQueriedDirList,
List<String> requiredQueryDirList) throws IOException {
List<String> newRequiredQueryDirList = new ArrayList<>(16);
initFtpClient();
try {
if(requiredQueryDirList.size() == 0) {
return;
}
for (int i = 0; i < requiredQueryDirList.size(); i++) {
String rootRemoteDir = requiredQueryDirList.get(i);
String rootLocalDir = storeDataMap.get(requiredQueryDirList.get(i));
// 獲取rootRemoteDir目錄下所有 檔案以及資料夾(或 獲取指定的檔案)
FTPFile[] ftpFiles = ftpClient.listFiles(rootRemoteDir);
for(FTPFile file : ftpFiles){
if (file.isDirectory()) {
String tempName = file.getName();
String ftpChildrenDir = "";
ftpChildrenDir = rootRemoteDir + "/" + tempName ;
String localChildrenDir = "";
localChildrenDir = rootLocalDir + "/" + tempName ;
alreadyQueriedDirList.add(ftpChildrenDir);
newRequiredQueryDirList.add(ftpChildrenDir);
storeDataMap.put(ftpChildrenDir, localChildrenDir);
}
}
}
} finally{
// 先登出、再關閉連線
ftpClient.logout();
if (ftpClient.isConnected()){
ftpClient.disconnect();
}
}
this.queryFTPAllChildrenDirectory(storeDataMap, alreadyQueriedDirList, newRequiredQueryDirList);
}
/**
* 根據給出的FTP目錄,查詢其所有子目錄以及子檔案(含其自身)
*
* @param alreadyQueriedDirList
* 所有已經查詢出來了的目錄
* @param alreadyQueriedFileList
* 所有已經查詢出來了的檔案
* @param requiredQueryDirList
* 還需要查詢的FTP目錄
* @throws IOException
* @DATE 2018年9月27日 上午12:12:53
*/
private void queryAllChildrenDirAndChildrenFile(List<String> alreadyQueriedDirList,
List<String> alreadyQueriedFileList,
List<String> requiredQueryDirList) throws IOException {
List<String> newRequiredQueryDirList = new ArrayList<>(16);
initFtpClient();
try {
if(requiredQueryDirList.size() == 0) {
return;
}
for (int i = 0; i < requiredQueryDirList.size(); i++) {
String dirPath = requiredQueryDirList.get(i);
// 獲取dirPath目錄下所有 檔案以及資料夾(或 獲取指定的檔案)
FTPFile[] ftpFiles = ftpClient.listFiles(dirPath);
for(FTPFile file : ftpFiles){
if (file.isDirectory()) {
String tempName = file.getName();
String ftpChildrenDir = dirPath + "/" + tempName;
alreadyQueriedDirList.add(ftpChildrenDir);
newRequiredQueryDirList.add(ftpChildrenDir);
} else {
String tempName = file.getName();
String ftpChildrenFile = dirPath + "/" + tempName;
alreadyQueriedFileList.add(ftpChildrenFile);
}
}
}
} finally{
// 先登出、再關閉連線
ftpClient.logout();
if (ftpClient.isConnected()){
ftpClient.disconnect();
}
}
this.queryAllChildrenDirAndChildrenFile(alreadyQueriedDirList, alreadyQueriedFileList, newRequiredQueryDirList);
}
/**
* 建立指定目錄(注:如果要建立的目錄已經存在,那麼返回false)
*
* @param dir
* 目錄路徑,絕對路徑,如: /abc 或 /abc/ 可以
* 相對路徑,如: sss 或 sss/ 也可以
* 注:相對路徑建立的資料夾所在位置時,相對於當前session所處目錄位置。
* 提示: .changeWorkingDirectory() 可切換當前session所處目錄位置
* @return 建立成功與否
* @throws IOException
* @DATE 2018年9月26日 下午3:42:20
*/
private boolean makeDirectory(String dir) throws IOException {
boolean flag = false;
flag = ftpClient.makeDirectory(dir);
if (flag) {
System.out.println(" FTPUtils -> makeDirectory -> create Dir [" + dir + "] success!");
} else {
System.err.println(" FTPUtils -> makeDirectory -> create Dir [" + dir + "] fail!");
}
return flag;
}
/**
* 在FTP伺服器上建立remoteDir目錄(不存在,則建立;存在,則不建立)
*
* @param remoteDir
* 要建立的目錄 為null或為"" 則視為 根目錄
* @return 結果
* @throws IOException
* @DATE 2018年9月26日 下午2:19:37
*/
private boolean CreateDirecroty(String remoteDir) throws IOException {
boolean success = true;
String directory = null;
if(remoteDir == null || remoteDir.trim().equals("")) {
directory = "/";
}else if(remoteDir.endsWith("/")) {
directory = remoteDir;
}else {
directory = remoteDir + "/";
}
// directory不為根目錄 且 切換至該目錄失敗 -> 說明FTPServer中不存在該目錄,那麼進行建立
/*
* .changeWorkingDirectory(directory)中的directory為 要切換到的目錄
* 可為 -> 絕對路徑; 可為 -> 相對路徑(如果為相對路徑,那麼相對於當前session所處目錄)
*/
if (!directory.equals("/") && !ftpClient.changeWorkingDirectory(directory)) {
// 獲得每一個節點目錄的起始位置
int start = 0;
int end = 0;
if (directory.startsWith("/")) {
start = 1;
} else {
start = 0;
}
end = directory.indexOf("/", start);
// 迴圈建立目錄
String dirPath = "";
String paths = "";
while (true) {
String subDirectory = directory.substring(start, end);
dirPath = dirPath + "/" + subDirectory;
if (!ftpClient.changeWorkingDirectory(dirPath)) {
makeDirectory(dirPath);
ftpClient.changeWorkingDirectory(dirPath);
// 當前session所處FTP目錄位置
String currentDirPath = ftpClient.printWorkingDirectory();
System.out.println(" FTPUtils -> current position dirPath ---> " + currentDirPath);
}
// 根性子節點目錄名 index起始位置
paths = paths + "/" + subDirectory;
start = end + 1;
end = directory.indexOf("/", start);
// 檢查所有目錄是否建立完畢
if (end < 0) {
break;
}
}
}
return success;
}
/**
* 避免在程式碼中頻繁 initFtpClient、logout、disconnect;
* 這裡包裝一下FTPClient的.changeWorkingDirectory(String pathname)方法
*
* @param directory
* 要切換(session)到FTP的哪一個目錄下
* @DATE 2018年9月27日 上午11:24:25
*/
private boolean ftputilsChangeWorkingDirectory(String pathname) throws IOException{
boolean result = true;
try {
initFtpClient();
result = ftpClient.changeWorkingDirectory(pathname);
}finally{
// 先登出、再關閉連線
ftpClient.logout();
if(ftpClient.isConnected()){
ftpClient.disconnect();
}
}
return result;
}
/**
* 判斷FTP上某目錄是否存在
*
* @param pathname
* 要判斷的路徑(檔名全路徑、資料夾全路徑都可以)
* 注:此路徑應從根目錄開始
* @DATE 2018年9月27日 上午11:24:25
*/
private boolean destDirExist(String pathname) throws IOException{
boolean result = true;
try {
// 初始化時,當前session位置即為 “/”
initFtpClient();
if (!pathname.startsWith("/")) {
pathname = "/" + pathname;
}
if (pathname.lastIndexOf(".") >= 0) {
int index = pathname.lastIndexOf("/");
if (index != 0) {
pathname = pathname.substring(0, index);
} else {
return true;
}
}
result = ftpClient.changeWorkingDirectory(pathname);
}finally{
// 先登出、再關閉連線
ftpClient.logout();
if(ftpClient.isConnected()){
ftpClient.disconnect();
}
}
return result;
}
}