首先把代碼貼出來:
?2?????public?static?void?main(String[]?args)?{
?3?????????String?url?=?"172.17.1.38";
?4?????????String?user?=?"test";
?5?????????String?pwd?=?"test";
?6?
?7?????????FTPClient?ftp?=?new?FTPClient();
?8?????????ftp.setControlEncoding("GBK");
?9?????????FTPClientConfig?conf?=?new?FTPClientConfig(FTPClientConfig.SYST_NT);
10?????????conf.setServerLanguageCode("zh");
11?????????ftp.configure(conf);
12?
13?????????try?{
14?????????????ftp.connect(url);
15?????????????if?(ftp.login(user,?pwd))?{
16?????????????????int?reply?=?ftp.getReplyCode();
17?????????????????if?(!FTPReply.isPositiveCompletion(reply))?{
18?????????????????????ftp.disconnect();
19?????????????????????System.out.println("disconnect");
20?????????????????}?else?{
21?????????????????????ftp.enterLocalPassiveMode();
22?????????????????????ftp.setFileType(FTP.BINARY_FILE_TYPE);
23?
24?????????????????????File?dir?=?new?File("down");
25?????????????????????if?(!dir.exists())?{
26?????????????????????????dir.mkdirs();
27?????????????????????}
28?
29?????????????????????String[]?names?=?ftp.listNames();
30?????????????????????for?(String?name?:?names)?{
31?????????????????????????File?file?=?new?File(dir.getPath()?+?File.separator?+?name);
32?????????????????????????if?(!file.exists())?{
33?????????????????????????????file.createNewFile();
34?????????????????????????}
35?????????????????????????long?pos?=?file.length();
36?????????????????????????RandomAccessFile?raf?=?new?RandomAccessFile(file,?"rw");
37?????????????????????????raf.seek(pos);
38?????????????????????????ftp.setRestartOffset(pos);
39?
40?????????????????????????InputStream?is?=?ftp.retrieveFileStream(name);
41?????????????????????????if?(is?==?null)?{
42?????????????????????????????System.out.println("no?such?file:"?+?name);
43?????????????????????????}?else?{
44?????????????????????????????System.out.println("start?getting?file:"?+?name);
45?
46?????????????????????????????int?b;
47?????????????????????????????while?((b?=?is.read())?!=?-1)?{
48?????????????????????????????????raf.write(b);
49?????????????????????????????}
50?????????????????????????????if?(ftp.getReply()?==?FTPReply.CODE_226)?{
51?????????????????????????????????System.out.println("done!");
52?????????????????????????????}
53?????????????????????????????is.close();
54?????????????????????????}
55?????????????????????????raf.close();
56?????????????????????}
57?????????????????}
58?????????????????ftp.logout();
59?????????????}
60?????????}?catch?(IOException?e)?{
61?????????????e.printStackTrace();
62?????????}
63?????}
64?}
一, 文件名中文亂碼問題.
開始知道能用FTPClient的listNames方法得到當前目錄下所有文件的列表. 但是發(fā)現(xiàn)中文文件名是亂碼. 默認情況下FTPClient使用UTF-8字符集作為和服務(wù)器通訊的編碼集. 而我們的ftp服務(wù)器是在中文windowsXP上裝的ServU. 所有使用GBK做為通訊編碼集. 經(jīng)過查找api文檔, 我看到了setControlEncoding方法, 試了一下,果然好使. 于是這個問題就解決了:
第8行: ftp.setControlEncoding("GBK")
至于conf.setServerLanguageCode("zh")對這個有什么影響,我還沒有驗證. 但是只有這句是不行的.
二, 傳輸binary文件, 由于FTPClient默認使用ASCII作為傳輸模式, 所有不能傳輸二進制文件. 通過
ftp.setFileType(FTP.BINARY_FILE_TYPE)個可以解決這個問題, 但是要在login以后執(zhí)行. 因為這個方法要向服務(wù)器發(fā)送"TYPE I"命令.
開始的時候用的是setFileTransferMode, 不過不好使. 它會執(zhí)行 MODE I命令, 服務(wù)器不接受.
三, 用被動模式傳輸: enterLocalPassiveMode()這個到不用在login之后執(zhí)行, 因為它只改變FTPClient實例的內(nèi)部屬性.
四, 斷點續(xù)傳. 心想應(yīng)該有支持吧, 于是查API結(jié)果找到了setRestartOffset()方法, 試了一下,果真好使. 用RandomAccessFile配合使用, 實現(xiàn)起來還是蠻簡單的.
五, 只能傳一個文件!!
不知道大家有沒有遇到這個問題, 傳輸?shù)谝粋€文件好使, 后面的的retrieveFileStream(name)都是返回null. 這個實在是令人頭痛的問題, 難不成要傳一個文件重新建立一次連接? 那樣也太土了吧. 但是文檔里也沒有寫, 來點狠的,debug它的源碼, 看看它究竟做了什么事情. 首先看一下ftp服務(wù)器的日志, 發(fā)現(xiàn)日志沒問題, 過來的命令和reply都是正確的, 但是發(fā)現(xiàn)第一個文件以后沒有執(zhí)行RETR命令. 于是跟蹤PASV命令的reply代碼,發(fā)現(xiàn)不是227,而服務(wù)器上的日志明明返回的是227. 難道是FTPClient解析Reply出問題了. 進一步跟蹤發(fā)現(xiàn)了問題, 原來在一個文件傳輸過程中會產(chǎn)生兩個Reply:
150 Opening BINARY mode data connection for a.sql (19890 Bytes).
226 Transfer complete.
而FTPClient自動消費掉一個,于是解析Reply就發(fā)生了錯位, 下一個命令的會解析266那條. 接下來的命令都不是解析自己的Reply而是前一次命令的. 所有在PASV命令的Reply碼就不對了, FTPClient也就不會執(zhí)行接下來本應(yīng)該執(zhí)行RETR命令.
他不消費,我們來消費吧. 于是在文件傳輸完成以后, 主動調(diào)用一次getReply()把接下來的226消費掉. 這樣做是可以解決這個暫時的問題, 但不知道在其他的ftp操作上會不會也有類似的情況. FTPClient這點可做的不大好.
對于上面這個問題, 我本來想修改一下FTPClient這個類來徹底解決問題. 結(jié)果發(fā)現(xiàn)自己也想不出好辦法. 最后還是放棄了.
完成的程序,上傳,下載,刪除
http://www.aygfsteel.com/Files/mstar/ClientTest.zip
比如:我在服務(wù)器上的文件是采用UTF-8或者gb2312或者unicode等等。
或者對別的語種,是否會因為強制指定了GBK而產(chǎn)生不可預(yù)料的編碼錯誤。
比如:法語、阿拉伯語、葡萄牙語等等。
獲取文件列表的時候,如果中間存在目錄結(jié)構(gòu)怎么辦?
直接createNewFile是不是會出現(xiàn)錯誤啊?
是不是需要考慮多層目錄嵌套的問題,采用迭代來分層獲取呢?
目前我的做法是:FTPFile[] ftpFiles = ftp.listXXX();具體的記不太清楚了。
然后判斷ftpFiles[i].isDirectory(),如果為true則使用changeWorkDirectory進入并獲取文件列表如果是目錄則繼續(xù)迭代。
不知道大家有沒有什么更好的方法實現(xiàn)。