在公司因为需要做一个从FTP服务器上下载文件的小程序,简单描述一下,后面直接上代码。

当应用程序被调用时,会从配置文件中读取配置信息,根据配置信息连接远程的FTP服务器,根据服务器上的文件的名称、文件的大小去数据库中查询数据。
数据库中存在: 不进行任何操作。
数据库中不存在:下载文件至本地,并且更新数据库信息。

具体实现代码:

public class FtpDownLoad {

    //从配置文件中获取配置信息
    private  String name;    //FTP名称
    private  String url;     //FTP服务器ip地址 
    private  int    port;    //FTP服务器端口  
    private  String username;//FTP登录账号  
    private  String password;//FTP登录密码  
    private  String rootPath;//FTP服务器上的相对路径
    private  String localpath;//下载后保存到本地的路径 

    private  FTPClient ftpClient; //连接FTP服务器的客户端

    //循环读取配置文件进行FTP采集信息
    public void execute(){
        Element element = ServiceConfigHelper.getServiceConfig("ftpConfig.xml");
        String elementValue = ServiceConfigHelper.getElementValue(element, "link-count");
        int count = Integer.parseInt(elementValue);
        for (int i = 0; i < count; i++) {
            Map<String, String> ftpMap = ServiceConfigHelper.getNextNodes("ftpConfig.xml", "ftp-"+(i+1));
            name = ftpMap.get("name");
            url = ftpMap.get("ip");
            port = Integer.parseInt(ftpMap.get("port"));
            username = ftpMap.get("username");
            password = ftpMap.get("password");
            rootPath = ftpMap.get("remotepath");
            localpath = ftpMap.get("localpath");
            //设置模式,默认为主动模式,如果配置文件中配置了被动模式设置,则为被动模式
            int type = ftpMap.get("passivemode")!=null?2:1;
            //循环调用采集的方法
            this.connectFTP(type);

            //下载文件
            this.ftpDownFiles(rootPath, localpath);
        }
        //采集完毕后,关闭资源
        if (ftpClient!=null && ftpClient.isConnected()) {
            try {
                ftpClient.logout();
                ftpClient.disconnect();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * @Title: connectFTP   
     * @Description: 连接FTP远程服务器 
     * @return boolean    是否连接成功  
     */
    public boolean connectFTP(int type){
        boolean flag = false;
        ftpClient = new FTPClient();
        int reply = 0;    
        try {
            ftpClient.connect(url, port);
            //解决中文乱码问题
            ftpClient.setControlEncoding("GBK");
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            //如果采用默认端口,可以使用ftp.connect(url)的方式直接连接FTP服务器     
            ftpClient.login(username, password);//登录     
            reply = ftpClient.getReplyCode();    
            if (!FTPReply.isPositiveCompletion(reply)) {    
                ftpClient.disconnect();    
                return flag;    
            }
            //默认为主动模式
            if (type==1) {
                ftpClient.enterLocalActiveMode();//主动模式
            }else if(type==2){
                ftpClient.enterLocalPassiveMode(); //被动模式
            }
            System.out.println("连接【"+this.name+"】FTP服务器成功!!");
            flag = true;
            return flag;
        } catch (SocketException e) {
            System.out.println("连接FTP服务器失败!!");
            e.printStackTrace();
        } catch (IOException e) {
            System.out.println("连接FTP服务器失败!!");
            e.printStackTrace();
        }    
        return flag;
    }

    /**
     * 
     * @Title: ftpDownFiles   
     * @Description: 从FTP服务器指定目录下载文件
     * @throws
     */
    public void ftpDownFiles(String ftpfilepath, String localpath) {

        if (ftpfilepath.length()>1) {
            if (!ftpfilepath.startsWith("/") || !ftpfilepath.endsWith("/")) {
                System.err.println("FTP服务器路径名称错误---"+ftpfilepath);
                return;
            }
        }
        try {
            FTPFile[] ff = ftpClient.listFiles(ftpfilepath);
            if (ff != null) {
                //循环遍历当前目录下的每一个文件
                for (FTPFile file : ff) {
                    //防止进入死循环
                    if (file.getName().equals(".") || file.getName().equals("..")) {
                        continue;
                    }
                    // 根据ftp文件生成相应本地文件
                    String localfilepath = localpath + file.getName();
                    File localFile = new File(localfilepath);
                    // 获取ftp文件最后修改时间
                    Date fflastModifiedDate = file.getTimestamp().getTime();
                    //获取ftp文件的大小
                    long size = file.getSize();
                    //System.out.println("\t\t"+(file.isDirectory()?"目录":"文件")+"名称为:"+file.getName());
                    // 如果是目录
                    if (file.isDirectory()) {
                        // 如果本地文件夹不存在就创建
                        localFile.mkdir();
                        // 转到ftp文件夹目录下
                        String ftpfp = ftpfilepath + file.getName() + "/";
                        // 转到本地文件夹目录下
                        String localfp = localfilepath+ "/";//+"/"
                        // 递归调用
                        //System.out.println("\t\t切换目录为:"+ftpClient.printWorkingDirectory());
                        this.ftpDownFiles(ftpfp, localfp);
                    }
                    else if (file.isFile()) {
                        // 如果是文件
                        File lFile = new File(localpath);
                        lFile.mkdir();
                        // 如果文件所在的文件夹不存在就创建
                        if (!lFile.exists()) {
                            return;
                        }
                        //FTP服务器上的文件全路径名称
                        String filepath = ftpfilepath + file.getName();
                        //if (file.getSize() != localFile.length() || result < 0) {
                        //判断文件是否需要下载
                        if (DBHelper.isDownLoad(filepath,size)) {
                            // 目标ftp文件下载路径
                            FileOutputStream fos = new FileOutputStream(
                                    localFile);
                            boolean boo = false;
                            try {
                                /**
                                 *从服务器检索一个命名文件并将其写入给定的OutputStream。 
                                 *此方法不会关闭给定的OutputStream。 
                                 *如果当前文件类型是ASCII,则文件中的行分隔符将转换为本地表示形式。
                                 * */
                                // 从FTP服务器上下载一个文件
                                boo = ftpClient.retrieveFile(new String(filepath.getBytes("GBK"),"ISO-8859-1"), fos);
                                if (boo) {
                                    System.out.println("\t文件【"+localFile.getAbsolutePath()+"】下载成功" );
                                    //保存至数据库
                                    SimpleDateFormat sFormat = new SimpleDateFormat("YYYY-MM-dd hh:mm:ss");
                                    String time = sFormat.format(fflastModifiedDate);
                                    DBHelper.saveInfo(filepath,size,time);
                                }else {
                                    System.err.println("\t文件【"+localFile.getAbsolutePath()+"】下载失败" );
                                }
                            } catch (Exception e) {
                                boo = false;
                                e.printStackTrace();
                            }
                            // 将缓冲区中的数据全部写出
                            fos.flush();
                            // 关闭流
                            fos.close();
                        }
                    }
                }
            }else{
                System.out.println("\t根目录下没有文件");
            }
        } catch (Exception e) {
             e.printStackTrace();
        }
    }

    //进行测试
    public static void main(String[] args) throws IOException {
        FtpDownLoad ftpDownload = new FtpDownLoad();
        //连接FTP服务器,采集信息
        ftpDownload.execute();
    }

}
代码注释已经比较详细,但是只支持中文文件名下载,但是中文目录下的文件并没有遍历到,不知道什么原因,希望懂的可以帮忙解决一下。

注释:
1. 从配置文件中获取ftp的连接信息(地址,用户名,密码,主被动连接等)
2. 从配置文件中获取数据库的连接信息
3. 动态生成本地文件