使用commons-net来下载文件(仅做记录)

使用 commons-net-3.6.jar

public class ApacheFtpUtil {
    private Logger log = LoggerFactory.getLogger(ApacheFtpUtil.class);
    private String host;
    private String username;
    private String password;
    // 控制端口
    private int port = 21;

    // 秒数
    private int defaultTimeoutSecond = 60;
    private int connectTimeoutSecond = 30;
    private int dataTimeoutSecond = 30;
    // 秒
    private int controlKeepAliveTimeout = 120;

    private boolean isTextMode = false;

    private String tranEncoding = "GB2312";

    private FTPClient client;

    public ApacheFtpUtil(String host, String username, String password) {
        this(host, username, password, 21, 0);
    }

    public ApacheFtpUtil(String host, String username, String password, int port) {
        this(host, username, password, port, 0);
    }

    public ApacheFtpUtil(String host, String username, String password, int port, int security) {
        this.host = host;
        this.port = port;
        this.username = username;
        this.password = password;
    }

    public void initClint() throws Exception {
        // FTPSClient
        client = new FTPClient();

        // 每大约2分钟发一次noop,防止大文件传输导致的控制连接中断
        client.setControlKeepAliveTimeout(controlKeepAliveTimeout);
        // client.setListHiddenFiles(listHiddenFiles);
        // FTPClientConfig config = new
        // FTPClientConfig(FTPClientConfig.SYST_NT);
        // config.setServerLanguageCode("zh");
        // config.setUnparseableEntries(saveUnparseable);
        // config.setDefaultDateFormatStr(defaultDateFormat);
        // config.setRecentDateFormatStr(recentDateFormat);
        // client.configure(config);

        // 设置默认超时
        client.setDefaultTimeout(defaultTimeoutSecond * 1000);
        // 连接超时
        // client.setConnectTimeout(connectTimeoutSecond * 1000);
        // 设置数据超时
        // client.setDataTimeout(dataTimeoutSecond * 1000);
        /*
         * socket超时 设置一个命令执行后最大等待Server反馈的时间. 如果对方连接状态60秒没有收到数据的话强制断开客户端
         */
        // client.setSoTimeout(60 * 1000);
        // client.setBufferSize(1024);
        // 连接到远程的FTP服务器.
        try {
            client.connect(this.host, this.port);
        } catch (Exception e) {
            this.destory();
            log.error("连接服务器失败,host:{}, port:{}", this.host, this.port);
            throw e;
        }
        int reply = client.getReplyCode(); // 获得返回的代码,来判断连接状态
        if (!FTPReply.isPositiveCompletion(reply)) {
            this.destory();
            // 连接错误
            throw new Exception("Can't Connect to :" + host);
        }
        // 登录
        boolean flag = client.login(this.username, this.password);
        if (flag == false) {
            this.destory();
            throw new Exception("Invalid user/password");
        }
        try {
            if (FTPReply.isPositiveCompletion(client.sendCommand("OPTS UTF8", "ON"))) {
                // 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码,否则就使用本地编码
                tranEncoding = "UTF-8";
                log.debug("FTP Server allow UTF8 encoding");
            }
        } catch (Exception e) {
            log.error("ftp server opts utf8 error,{}", e.getMessage());
        }
        log.info("use encoding {}", tranEncoding);
        client.setControlEncoding(tranEncoding); // 中文支持
        // 设置传送模式
        if (isTextMode) {
            client.setFileType(FTP.ASCII_FILE_TYPE);
        } else {
            client.setFileType(FTP.BINARY_FILE_TYPE);
        }
        /*
         * PORT中文称为主动模式,工作的原理:
         * FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录,登录成功后要list列表或者读取数据时,
         * 客户端随机开放一个端口(1024以上),发送 PORT命令到FTP服务器,告诉服务器客户端采用主动模式并开放端口;
         * FTP服务器收到PORT主动模式命令和端口号后,通过服务器的20端口和客户端开放的端口连接,发送数据.
         * 主动模式需要客户端必须开放端口给服务器,很多客户端都是在防火墙内,开放端口给FTP服务器访问比较困难。
         */
        // client.enterLocalActiveMode(); //主动模式
        /*
         * PASV是Passive的缩写,中文成为被动模式.
         * 工作原理:FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录,登录成功后要list列表或者读取数据时,
         * 发送PASV命令到FTP服务器, 服务器在本地随机开放一个端口(1024以上),然后把开放的端口告诉客户端,
         * 客户端再连接到服务器开放的端口进行数据传输. 被动模式只需要服务器端开放端口给客户端连接就行了。
         */
        client.enterLocalPassiveMode();
        // client.setUseEPSVwithIPv4(useEpsvWithIPv4);
        log.debug("==========初始化FTP连接成功===========");
    }

    public void destory() {
        if (client == null) {
            return;
        }
        try {
            client.logout();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            client.disconnect();
        } catch (IOException e) {
            e.printStackTrace();
        }
        client = null;
    }

    public void changeRemoteDir(String newPath) throws RuntimeException {
        // 切换路径[相对路径和绝对路径都可]
        if (StringUtils.isBlank(newPath)) {
            return;
        }
        try {
            boolean flag = client.changeWorkingDirectory(new String(newPath.getBytes(tranEncoding), "ISO-8859-1"));
            log.debug("change working directory to {}, status:{}", newPath, flag);
        } catch (IOException e) {
            throw new RuntimeException("切换路径失败:" + newPath + "; " + e.getMessage());
        }
    }

    /**
     * 下载文件
     */
    public void download(String remoteFile, String localOutFile) throws RuntimeException {
        FileOutputStream outstream = null;
        // 下载文件
        try {
            log.debug("开始下载文件 {}", remoteFile);
            outstream = new FileOutputStream(new File(localOutFile));
            /*
             * 这个方法的意思就是每次数据连接之前,ftp client告诉ftp server开通一个端口来传输数据. 因为ftp
             * server可能每次开启不同的端口来传输数据,但是在linux上,由于安全限制,可能某些端口没有开启,所以就出现阻塞
             */
            client.enterLocalPassiveMode();
            client.setFileType(FTP.BINARY_FILE_TYPE);
            /*
             * FTP协议里面,规定文件名编码为iso-8859-1,所以目录名或文件名需要转码 retrieveFile的第一个参数需要是
             * ISO-8859-1 编码
             */
            client.retrieveFile(new String(remoteFile.getBytes(tranEncoding), "ISO-8859-1"), outstream);
        } catch (IOException e) {
            throw new RuntimeException("下载文件失败:" + remoteFile + "; " + e.getMessage());
        } finally {
            if (outstream != null) {
                try {
                    outstream.flush();
                    outstream.close();
                } catch (IOException e) {
                }
            }
        }
        log.debug("下载文件 {} 完成", remoteFile);
    }
}

猜你喜欢

转载自blog.51cto.com/dengshuangfu/2130277