這段時間一直忙着項目開發,沒顧上寫總結。今天抽點時間對於之前遇到的ftp上傳文件無應答的問題總結一下,方便自己以後查看,也方便下個遇到此問題的人能夠快速的解決問題。
使用Apache的開源框架寫的一個很簡單的ftp上傳的demo,如果網絡環境穩定的情況下上傳文件不會有問題,也能得到服務器文件傳完後的響應狀態,但是遇到大文件和網絡不好的情況下,上傳文件時間比較長(半個小時以上),這時執行ftpClient.storeFile("test.ts", in)這句代碼會卡在這裏,即使文件傳完了也不會做出響應,得不到服務器的響應代碼就不會繼續往下執行,線程也就會一直停在這裏。下面是一個簡單的文件ftp上傳demo:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
public class FtpUtil {
public static void main(String[] args) {
FTPClient ftpClient = new FTPClient();
try {
// 連接指定服務器,默認端口爲21
ftpClient.connect("127.0.0.1");
System.out.println("connect to server");
// 獲取響應字符串(FTP服務器上可設置)
String replyString = ftpClient.getReplyString();
System.out.println("replyString: " + replyString);
// 獲取響應碼用於驗證是否連接成功
int reply = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
System.out.println(reply);
System.exit(1);
}
// 設置鏈接編碼,windows主機UTF-8會亂碼,需要使用GBK或gb2312編碼
ftpClient.setControlEncoding("GBK");
// 登錄服務器
boolean login = ftpClient.login("ceshi", "ceshi");
if (login) {
System.out.println("登錄成功!");
} else {
System.out.println("登錄失敗!");
}
// 獲取所有文件和文件夾的名字
FTPFile[] files = ftpClient.listFiles();
for (FTPFile file : files) {
if (file.isDirectory()) {
System.out.println(file.getName() + " 是文件夾");
}
if (file.isFile()) {
System.out.println(file.getName() + " 是文件");
}
}
// 生成InputStream用於上傳本地文件
InputStream in = new FileInputStream("e:\\ceshi.txt");
// 上傳文件
boolean result = ftpClient.storeFile("test.txt", in);
if (result) {
System.out.println("上傳成功!");
}
in.close();
// 註銷登錄
boolean logout = ftpClient.logout();
if (logout) {
System.out.println("註銷成功!");
} else {
System.out.println("註銷失敗!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 關閉鏈接需要放在finally語句塊中
if (ftpClient.isConnected()) {
try {
ftpClient.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
解決方案:
遇到這樣的問題剛開始不知道怎麼回事,經過一番排查後找到了問題的原因,最後給出下面兩種解決方法。
1、這個框架提供了多種上傳方法,比如:
可以通過使用直接獲取遠程目錄創建文件、然後拿到輸出流將文件寫入,這樣可以手動控制文件的上傳,也可以實現斷點續傳。這是一種辦法,推薦使用這種辦法。
2、這個方案是通過主線程和子線程的方式來實現,將文件上傳放在子線程裏,主線程負責開啓上傳子線程和監聽子線程文件上傳是否完成,如果遇到不響應的情況,主線程會判斷文件上傳是否完成,如果完成則強制關閉子線程使用的文件流,然後讀取新的文件繼續開啓新的線程來執行上傳。