首先把代码贴出来:
java 代码
- public class ClientTest {
- public static void main(String[] args) {
- String url = "172.17.1.38";
- String user = "test";
- String pwd = "test";
- FTPClient ftp = new FTPClient();
- ftp.setControlEncoding("GBK");
- FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);
- conf.setServerLanguageCode("zh");
- ftp.configure(conf);
- try {
- ftp.connect(url);
- if (ftp.login(user, pwd)) {
- int reply = ftp.getReplyCode();
- if (!FTPReply.isPositiveCompletion(reply)) {
- ftp.disconnect();
- System.out.println("disconnect");
- } else {
- ftp.enterLocalPassiveMode();
- ftp.setFileType(FTP.BINARY_FILE_TYPE);
- File dir = new File("down");
- if (!dir.exists()) {
- dir.mkdirs();
- }
- String[] names = ftp.listNames();
- for (String name : names) {
- File file = new File(dir.getPath() + File.separator + name);
- if (!file.exists()) {
- file.createNewFile();
- }
- long pos = file.length();
- RandomAccessFile raf = new RandomAccessFile(file, "rw");
- raf.seek(pos);
- ftp.setRestartOffset(pos);
- InputStream is = ftp.retrieveFileStream(name);
- if (is == null) {
- System.out.println("no such file:" + name);
- } else {
- System.out.println("start getting file:" + name);
- int b;
- while ((b = is.read()) != -1) {
- raf.write(b);
- }
- if (ftp.getReply() == FTPReply.CODE_226) {
- System.out.println("done!");
- }
- is.close();
- }
- raf.close();
- }
- }
- ftp.logout();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
一, 文件名中文乱码问题.
开始知道能用FTPClient的listNames方法得到当前目录下所有文件的列表. 但是发现中文文件名是乱码. 默认情况下FTPClient使用UTF-8字符集作为和服务器通讯的编码集. 而我们的ftp服务器是在中文windowsXP上装的ServU. 所有使用GBK做为通讯编码集. 经过查找api文档, 我看到了setControlEncoding方法, 试了一下,果然好使. 于是这个问题就解决了:
第8行: ftp.setControlEncoding("GBK")
至于conf.setServerLanguageCode("zh")对这个有什么影响,我还没有验证. 但是只有这句是不行的.
二, 传输binary文件, 由于FTPClient默认使用ASCII作为传输模式, 所有不能传输二进制文件. 通过
ftp.setFileType(FTP.BINARY_FILE_TYPE)个可以解决这个问题, 但是要在login以后执行. 因为这个方法要向服务器发送"TYPE I"命令.
开始的时候用的是setFileTransferMode, 不过不好使. 它会执行 MODE I命令, 服务器不接受.
三, 用被动模式传输: enterLocalPassiveMode()这个到不用在login之后执行, 因为它只改变FTPClient实例的内部属性.
四, 断点续传. 心想应该有支持吧, 于是查API结果找到了setRestartOffset()方法, 试了一下,果真好使. 用RandomAccessFile配合使用, 实现起来还是蛮简单的.
五, 只能传一个文件!!
不知道大家有没有遇到这个问题, 传输第一个文件好使, 后面的的retrieveFileStream(name)都是返回null. 这个实在是令人头痛的问题, 难不成要传一个文件重新建立一次连接? 那样也太土了吧. 但是文档里也没有写, 来点狠的,debug它的源码, 看看它究竟做了什么事情. 首先看一下ftp服务器的日志, 发现日志没问题, 过来的命令和reply都是正确的, 但是发现第一个文件以后没有执行RETR命令. 于是跟踪PASV命令的reply代码,发现不是227,而服务器上的日志明明返回的是227. 难道是FTPClient解析Reply出问题了. 进一步跟踪发现了问题, 原来在一个文件传输过程中会产生两个Reply:
150 Opening BINARY mode data connection for a.sql (19890 Bytes).
226 Transfer complete.
而FTPClient自动消费掉一个,于是解析Reply就发生了错位, 下一个命令的会解析266那条. 接下来的命令都不是解析自己的Reply而是前一次命令的. 所有在PASV命令的Reply码就不对了, FTPClient也就不会执行接下来本应该执行RETR命令.
他不消费,我们来消费吧. 于是在文件传输完成以后, 主动调用一次getReply()把接下来的226消费掉. 这样做是可以解决这个暂时的问题, 但不知道在其他的ftp操作上会不会也有类似的情况. FTPClient这点可做的不大好.
对于上面这个问题, 我本来想修改一下FTPClient这个类来彻底解决问题. 结果发现自己也想不出好办法. 最后还是放弃了.
本文分享了使用 Jakarta Commons Net 中的 FTPClient 实现文件上传下载过程中的经验总结,包括解决文件名中文乱码、传输二进制文件、被动模式传输、断点续传等问题的方法。
2419

被折叠的 条评论
为什么被折叠?



