使用FTP传输文件/同步文件

  • FTP安装
  • FTP工具类
  • 文件同步工具类
  • FTP工具类

FTP安装

首先,我们执行安装命令:yum install -y vsftpd

如果没有yum需要下载安装(自行百度)

ftp 同步到 ftp java ftp同步文件_ftp 同步到 ftp java


安装成功后我们进入FTP文件夹查看是否有问题,FTP在Linux上名称为 vsftpd ,默认安装在 /etc/vsftpd 目录下:

ftp 同步到 ftp java ftp同步文件_服务器_02

ftpusers  黑名单文件,此文件里的用户不允许访问 FTP 服务器
user_list  白名单文件,是允许访问 FTP 服务器的用户列表
vsftpd.conf  核心配置文件
vsftpd_conf_migrate.sh  FTP服务

安装完成之后先不要着急配置,我们先给Linux系统添加一个用户,一个登录FTP服务器的用户:

ftp 同步到 ftp java ftp同步文件_java_03

这里需要限制FTP登录的人数,我们进入 vsftpd 目录下的 user_list 中修改,如下:

ftp 同步到 ftp java ftp同步文件_ftp 同步到 ftp java_04


user_list 里面的内容是能够登录FTP的用户列表,若是不想让其他用户登录,则删除该文件内的其他用户名,仅保留我们刚才创建的一个用户(root为系统管理员,若是不需要也可以删除)。

完成以上步骤我们接下来要配置 vsftpd.conf 这个核心文件,此配置我们仅需要修改一个地方,就是匿名用户登录的时候将其禁止,然后指定FTP根目录就行了,其他的也可以自行查找网上的一些方式来配置。

ftp 同步到 ftp java ftp同步文件_ftp_05


ftp 同步到 ftp java ftp同步文件_ftp_06


ftp 同步到 ftp java ftp同步文件_ftp_07

开启vsftpd服务

service vsftpd start

补充:FTP日志功能配置

xferlog_enable=YES //开启日志功能
xferlog_file=/var/log/xferlog //日志文件的存放位置
xferlog_std_format=YES //使用标准格式记录日志

xferlog该日志文件记录了FTP会话,可以显示出用户向从FTP服务器拷贝了什么文件。其中一条记录如下:

Thu Feb 16 10:09:05 2017 1 10.10.10.9 990 ./home/ftpie.txt b _ o r test ftp 0 * c

数据参数说明

记录数据

参数名称

参数说明

Thu Feb 16 10:09:05

当前时间

当前服务器本地时间

1

传输时间

传送文件所用时间,单位为秒

10.10.10.9

远程主机名称/IP

远程主机名称/IP

990

文件大小

传送文件的大小,单位为byte

./home/ftpie.txt

文件名

传输文件名,包括路径

b

传输类型

传输方式的类型,包括两种:

a以ASCII传输

b以二进制文件传输


特殊处理标志

特殊处理的标志位,可能的值包括:

_ 不做任何特殊处理

C 文件是压缩格式

U 文件是非压缩格式

T 文件是tar格式

o

传输方向

文件传输方向,包括两种:

o 从FTP服务器向客户端传输

i 从客户端向FTP服务器传输

r

访问模式

用户访问模式,包括:

a 匿名用户

g 来宾用户

r 真实用户,即系统中的用户

test

用户名

用户名称

ftp

服务名

所使用的服务名称,一般为FTP

0

认证方式

认证方式,包括:

0 无</br/>1 RFC931认证

*

认证用户id

认证用户的id,如果使用*,则表示无法获得该id

c

完成状态

传输的状态:

c 表示传输已完成

i 表示传输示完成

注意:防火墙需要开启ftp服务的端口

firewall-cmd --add-service=ftp --permanent
firewall-cmd --reload

FTP工具类

文件同步工具类

public class FileSyncUtils {
    public final static String LOG_FILE_DIR = "f:/ftp/log";
    public final static String FILESYSC_FILE_PATH = "f:/ftp/filesync.ini";
    public static FileWriter fileWriter = null;
    public static Long currTimestamp = 0L;   //时间戳


    //获取需要同步的文件,返回false:没有需要同步的文件,true:有文件需要同步
    public static boolean getSyncFile(List<File> lstFile, IniEditor iniInfo) throws IOException {

        String srcdir = iniInfo.get("FILESYNC", "SRCDIR");
        String timestamp = iniInfo.get("FILESYNC", "TIMESTAMP");

        //本地同步目录
        File locDir = new File(srcdir);

        //查询需要同步的文件,并存放在lstFile中(记录在filesync.ini文件的时间戳:timestamp)
        qryFile(locDir, lstFile, Long.valueOf(timestamp));

        int len = lstFile.size();

        //日志文件不存在,则创建该日志文件(日志文件:sync_yyyyMMdd.log)
        String logFile = getLogFile(LOG_FILE_DIR);
        fileWriter = new FileWriter(logFile, true);
        fileWriter.write("\n\n" + dateFormat(new Date(), "yyyy-MM-yy HH:mm:ss") + "----> 文件同步开始......");

        if (len == 0) {
            fileWriter.write("\n" + dateFormat(new Date(), "yyyy-MM-yy HH:mm:ss") + "----> 没有需要同步的文件!");
            fileWriter.close();
            return false;
        } else {
            fileWriter.write("\n" + dateFormat(new Date(), "yyyy-MM-yy HH:mm:ss") + "----> 文件扫描完成,需要同步文件 " + len + " 个,同步开始");
        }

        //对存放在lstFile中的文件按修改时间排序
        File file = null;
        for (int i = 0; i < len; i++) {
            for (int j = 0; j < len - 1; j++) {
                if (lstFile.get(j).lastModified() > lstFile.get(j + 1).lastModified()) {
                    file = lstFile.get(j);
                    lstFile.set(j, lstFile.get(j + 1));
                    lstFile.set(j + 1, file);
                }
            }
        }

        System.out.println("***************************************");
        for (File f : lstFile) {
            System.out.println(f.getAbsolutePath());
        }
        System.out.println("***************************************");
        return true;
    }

    public static void main(String[] args) throws IOException {

        //读取filesync.ini文件配置
        IniEditor iniInfo = getIniInfo(FILESYSC_FILE_PATH);

        List<File> lstFile = new ArrayList<File>();

        //获取排好的需要同步的文件lstFile
        boolean b = getSyncFile(lstFile, iniInfo);

        if (!b) {
            return;
        }
        boolean res = false;

        //同步本地文件到FTP服务器
        res = syncFiles(lstFile, iniInfo);


        //同步成功时,才保存时间戳,否则不保存时间戳
        if (res) {
            iniInfo.set("FILESYNC", "TIMESTAMP", String.valueOf(currTimestamp));
            iniInfo.save(new File(FILESYSC_FILE_PATH));
        }

    }

    public static boolean syncFiles(List<File> lstFile, IniEditor iniInfo) throws IOException {

        String srcdir = iniInfo.get("FILESYNC", "SRCDIR");
        String server = iniInfo.get("FILESYNC", "SERVER");
        String port = iniInfo.get("FILESYNC", "PORT");
        String user = iniInfo.get("FILESYNC", "USER");
        String password = iniInfo.get("FILESYNC", "PASSWORD");

        if (fileWriter == null) {
            String logFile = getLogFile(LOG_FILE_DIR);
            fileWriter = new FileWriter(logFile, true);
        }

        //写日志文件

        //时间戳
        currTimestamp = Long.valueOf(dateFormat(new Date(), "yyyyMMddHHmmss"));

        fileWriter.write("\n" + dateFormat(new Date(), "yyyy-MM-yy HH:mm:ss") + "----> 开始同步文件,时间戳为:" + currTimestamp);

        //本地目录的字符数
        int n = srcdir.length();

        //同步List
        List<File> syncList = Collections.synchronizedList(lstFile);

        FTPClient ftpClient = new FTPClient();

        //登陆FTP
        boolean b_login = loginFtp(ftpClient, server, Integer.valueOf(port), user, password, fileWriter);

        if (!b_login) {
            fileWriter.write("\n" + dateFormat(new Date(), "yyyy-MM-yy HH:mm:ss") + "---->  登陆FTP失败......");
            if (fileWriter != null) {
                fileWriter.close();
            }
            return false;
        }

        // 设置被动模式
        ftpClient.enterLocalPassiveMode();

        // 设置以二进制方式传输,不能设置此选项
        ftpClient.setFileType(FTP.BINARY_FILE_TYPE);

        //下面三行代码必须要,而且不能改变编码格式
        ftpClient.setControlEncoding("GBK");
        FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);
        conf.setServerLanguageCode("zh");


        boolean b = false;

        //循环上传需要同步的文件到FTP服务器上
        for (File f : syncList) {
            synchronized (FileSyncUtils.class) {
                f.getParentFile().getPath();
                String path = f.getParentFile().getPath().substring(n - 1);
                InputStream input = new FileInputStream(f);
                path = new String(path.getBytes("GBK"), "ISO8859-1");
                String filename = new String(f.getName().getBytes("GBK"), "ISO8859-1");

                b = uploadFile(ftpClient, path, filename, input, fileWriter);

                if (!b) {
                    try {
                        Thread.sleep(1000);
                        for (int i = 1; i <= 10; i++) {
                            input = new FileInputStream(f);
                            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~  ---> path=" + new String(path.getBytes("ISO8859-1"), "GBK"));
                            b = uploadFile(ftpClient, path, filename, input, fileWriter);

                            System.err.println("~~~~~~~~~~~~~~~~~~~~   --->" + i + "  " + new String(filename.getBytes("ISO8859-1"), "GBK") + "--->" + (b) + "~~~~~~~~~~~~~~~~~~");
                            if (b) {
                                fileWriter.write("\n" + dateFormat(new Date(), "yyyy-MM-yy HH:mm:ss")
                                        + "----> 文件[" + new String(filename.getBytes("ISO8859-1"), "GBK") + "]同步成功!");
                                break;
                            } else {
                                fileWriter.write("\n" + dateFormat(new Date(), "yyyy-MM-yy HH:mm:ss")
                                        + "----> 文件[" + new String(filename.getBytes("ISO8859-1"), "GBK")
                                        + "]同步失败,错误原因:上传该文件时出现异常!");
                            }
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    //最终还是有文件不能成功 上传,则退出程序
                    if (!b) {
                        break;
                    }
                } else {
                    input.close();
                }

            }
        }


        ftpClient.logout();
        ftpClient.disconnect();

        if (b) {
            fileWriter.write("\n" + dateFormat(new Date(), "yyyy-MM-yy HH:mm:ss") + "---->文件同步完成,共同步文件" + lstFile.size() + " 个");
        } else {
            fileWriter.write("\n" + dateFormat(new Date(), "yyyy-MM-yy HH:mm:ss") + "---->文件同步失败......");
        }
        if (fileWriter != null) {
            fileWriter.close();
        }
        return b;
    }

    //加载filesysc.ini文件
    public static IniEditor getIniInfo(String fileName) {
        File file = new File(fileName);
        IniEditor ini = new IniEditor();
        try {
            ini.load(file);
        } catch (IOException e) {
            System.out.println("获取filesysc.ini文件信息时,出现异常");
            e.printStackTrace();
        }
        return ini;
    }

    //登陆FTP
    public static boolean loginFtp(FTPClient ftpClient, String server, int port, String user, String password, FileWriter fileWriter) {
        boolean b = false;
        try {
            ftpClient.connect(server, port);
            int reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                throw new IOException("Can't connect to server '" + server + "'");
            }
            b = ftpClient.login(user, password);
        } catch (Exception e) {
            try {
                fileWriter.write("\n" + dateFormat(new Date(), "yyyy-MM-yy HH:mm:ss") + "---->" + e.getMessage());
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
        return b;
    }

    //得到日志文件绝对路径,不存在则创建
    public static String getLogFile(String path) throws IOException {
        File dir = new File(path);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        String logFile = path + "/sync_" + dateFormat(new Date(), "yyyyMMdd") + ".log";
        File file = new File(logFile);

        if (!file.exists()) {
            file.createNewFile();
        }
        return logFile;
    }

    //格式化时间
    public static String dateFormat(Date date, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }

    //查询目录中大于时间戳的所有文件
    public static void qryFile(File file, List<File> lstFile, long timestamp) {

        if (file.isFile() && timestamp < Long.valueOf(dateFormat(new Date(file.lastModified()), "yyyyMMddHHmmss"))) {
            System.err.println("递归文件------------->" + file.getPath());
            lstFile.add(file);
        } else {
            System.err.println("递归文件夹-------------->" + file.getPath());
            File[] files = file.listFiles();
            for (File f : files) {
                if (f.isFile() && timestamp < Long.valueOf(dateFormat(new Date(f.lastModified()), "yyyyMMddHHmmss"))) {
                    lstFile.add(f);
                    System.out.println("递归文件-------------->" + f.getPath());
                } else if (f.isDirectory()) {
                    qryFile(f, lstFile, timestamp);
                }
            }
        }
    }

    /**
     * Description: 向FTP服务器 单个上传文件
     *
     * @param path     FTP服务器保存目录
     * @param filename 上传到FTP服务器上的文件名
     * @param input    输入流
     * @return 成功返回true,否则返回false
     * @throws IOException
     */
    public static boolean uploadFile(FTPClient ftpClient, String path, String filename, InputStream input, FileWriter writer) {
        boolean success = false;
        String pth = path;
        try {
            //切换到默认目录
            ftpClient.changeWorkingDirectory("");

            //切换FTP服务器存放文件的目录
            if (!"".equals(pth)) {
                pth = pth.replace("\\", "/");
                String[] arr = pth.split("/");

                for (String p : arr) {
                    p = p.trim();
                    if (!"".equals(p)) {
                        if (!ftpClient.changeWorkingDirectory(p)) {
                            ftpClient.makeDirectory(p);
                        }
                        //切换FTP目录
                        ftpClient.changeWorkingDirectory(p);
                    }
                }
            }

            ftpClient.enterLocalPassiveMode();

            //删除该目录上的同名文件
            ftpClient.deleteFile(filename);


            System.out.println("---------------------> uploadFile filename=" + new String(filename.getBytes("ISO8859-1"), "GBK"));

            success = ftpClient.storeFile(filename, input);

            if (input != null) {
                input.close();
            }

        } catch (IOException e) {

            try {
                if (input != null) {
                    input.close();
                }

                System.err.println("上传" + new String(filename.getBytes("ISO8859-1"), "GBK") + "    失败......");
                if (input != null) {
                    input.close();
                }
            } catch (UnsupportedEncodingException e3) {
                e3.printStackTrace();
            } catch (IOException e1) {
                e1.printStackTrace();
            }

        }
        return success;
    }

}

FTP工具类

@Slf4j
public class FtpUtils {
    public static final String ANONYMOUS_LOGIN = "anonymous";
    private FTPClient ftp;
    private boolean is_connected;

    public FtpUtils() {
        ftp = new FTPClient();
        is_connected = false;
    }

    public FtpUtils(int defaultTimeoutSecond, int connectTimeoutSecond, int dataTimeoutSecond) {
        ftp = new FTPClient();
        is_connected = false;

        ftp.setDefaultTimeout(defaultTimeoutSecond * 1000);
        ftp.setConnectTimeout(connectTimeoutSecond * 1000);
        ftp.setDataTimeout(dataTimeoutSecond * 1000);
    }

    public boolean getIs_connected() {
        return is_connected;
    }

    /**
     * Connects to FTP server.
     *
     * @param host       FTP server address or name
     * @param port       FTP server port
     * @param user       user name
     * @param password   user password
     * @param isTextMode text / binary mode switch
     * @throws IOException on I/O errors
     */
    public void connect(String host, int port, String user, String password, boolean isTextMode) throws IOException {
        final ExecutorService exec = Executors.newFixedThreadPool(1);
        // Connect to server.
        try {
            ftp.connect(host, port);
        } catch (UnknownHostException ex) {
            throw new IOException("Can't find FTP server '" + host + "'");
        }

        // Check rsponse after connection attempt.
        int reply = ftp.getReplyCode();
        if (!FTPReply.isPositiveCompletion(reply)) {
            disconnect();
            throw new IOException("Can't connect to server '" + host + "'");
        }

        if (user == "") {
            user = ANONYMOUS_LOGIN;
        }
        String finalUser = user;
        Callable<String> call = new Callable<String>() {
            @Override
            public String call() throws Exception {
                ftp.login(finalUser, password);
                return "登录成功!";
            }
        };
        try {
            Future<String> future = exec.submit(call);
            // 任务处理超时时间设置
            String obj = future.get(4 * 1000, TimeUnit.MILLISECONDS);
            int replyCode = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(replyCode)) {
                throw new AccountException("ftp远程登录失败(用户名或密码错误)!");
            }
            is_connected = true;
            log.info("ftp登录:" + obj);
        } catch (AccountException e) {
            is_connected = false;
            throw new IOException(e.getMessage());
        } catch (TimeoutException ex) {
            is_connected = false;
            log.error("ftp登录超时!");
            throw new IOException("ftp登录超时!");
        } catch (Exception e) {
            if (!FTPReply.isPositiveCompletion(reply)) {
                disconnect();
            }
            log.error("Can't login to server '" + host + "'");
        }
        // 关闭线程池
        exec.shutdown();
        // Set data transfer mode.
        if (isTextMode) {
            ftp.setFileType(FTP.ASCII_FILE_TYPE);
        } else {
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
        }
    }

    /**
     * Uploads the file to the FTP server.
     *
     * @param ftpFileName server file name (with absolute path)
     * @param localFile   local file to upload
     * @throws IOException on I/O errors
     */
    public void upload(String ftpFileName, File localFile) throws IOException {
        // File check.
        if (!localFile.exists()) {
            throw new IOException("Can't upload '" + localFile.getAbsolutePath() + "'. This file doesn't exist.");
        }

        // Upload.
        InputStream in = null;
        try {

            // Use passive mode to pass firewalls.
            ftp.enterLocalPassiveMode();

            in = new BufferedInputStream(new FileInputStream(localFile));
            if (!ftp.storeFile(ftpFileName, in)) {
                throw new IOException("Can't upload file '" + ftpFileName + "' to FTP server. Check FTP permissions and path.");
            }

        } finally {
            try {
                in.close();
            } catch (IOException ex) {
            }
        }
    }

    /**
     * Downloads the file from the FTP server.
     *
     * @param ftpFileName server file name (with absolute path)
     * @param localFile   local file to download into
     * @throws IOException on I/O errors
     */
    public void download(String ftpFileName, File localFile) throws IOException {
        // Download.
        OutputStream out = null;
        try {
            // Use passive mode to pass firewalls.
            ftp.enterLocalPassiveMode();

            // Get file info.
            FTPFile[] fileInfoArray = ftp.listFiles(ftpFileName);
            if (fileInfoArray == null) {
                throw new FileNotFoundException("File " + ftpFileName + " was not found on FTP server.");
            }

            // Check file size.
            FTPFile fileInfo = fileInfoArray[0];
            long size = fileInfo.getSize();
            if (size > Integer.MAX_VALUE) {
                throw new IOException("File " + ftpFileName + " is too large.");
            }

            // Download file.
            out = new BufferedOutputStream(new FileOutputStream(localFile));
            if (!ftp.retrieveFile(ftpFileName, out)) {
                throw new IOException("Error loading file " + ftpFileName + " from FTP server. Check FTP permissions and path.");
            }

            out.flush();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException ex) {
                }
            }
        }
    }

    /**
     * Removes the file from the FTP server.
     *
     * @param ftpFileName server file name (with absolute path)
     * @throws IOException on I/O errors
     */
    public void remove(String ftpFileName) throws IOException {
        if (!ftp.deleteFile(ftpFileName)) {
            throw new IOException("Can't remove file '" + ftpFileName + "' from FTP server.");
        }
    }

    /**
     * Lists the files in the given FTP directory.
     *
     * @param filePath absolute path on the server
     * @return files relative names list
     * @throws IOException on I/O errors
     */
    public List<String> list(String filePath) throws IOException {
        List<String> fileList = new ArrayList<String>();

        // Use passive mode to pass firewalls.
        ftp.enterLocalPassiveMode();

        FTPFile[] ftpFiles = ftp.listFiles(filePath);
        int size = (ftpFiles == null) ? 0 : ftpFiles.length;
        for (int i = 0; i < size; i++) {
            FTPFile ftpFile = ftpFiles[i];
            if (ftpFile.isFile()) {
                fileList.add(ftpFile.getName());
            }else {

            }
        }

        return fileList;
    }

    /**
     * Sends an FTP Server site specific command
     *
     * @param args site command arguments
     * @throws IOException on I/O errors
     */
    public void sendSiteCommand(String args) throws IOException {
        if (ftp.isConnected()) {
            try {
                ftp.sendSiteCommand(args);
            } catch (IOException ex) {
            }
        }
    }

    /**
     * Disconnects from the FTP server
     *
     * @throws IOException on I/O errors
     */
    public void disconnect() throws IOException {

        if (ftp.isConnected()) {
            try {
                ftp.logout();
                ftp.disconnect();
                is_connected = false;
            } catch (IOException ex) {
            }
        }
    }

    /**
     * Makes the full name of the file on the FTP server by joining its path and
     * the local file name.
     *
     * @param ftpPath   file path on the server
     * @param localFile local file
     * @return full name of the file on the FTP server
     */
    public String makeFTPFileName(String ftpPath, File localFile) {
        if (ftpPath == "") {
            return localFile.getName();
        } else {
            String path = ftpPath.trim();
            if (path.charAt(path.length() - 1) != '/') {
                path = path + "/";
            }

            return path + localFile.getName();
        }
    }

    /**
     * Test coonection to ftp server
     *
     * @return true, if connected
     */
    public boolean isConnected() {
        return is_connected;
    }

    /**
     * Get current directory on ftp server
     *
     * @return current directory
     */
    public String getWorkingDirectory() {
        if (!is_connected) {
            return "";
        }

        try {
            return ftp.printWorkingDirectory();
        } catch (IOException e) {
        }

        return "";
    }

    /**
     * Set working directory on ftp server
     *
     * @param dir new working directory
     * @return true, if working directory changed
     */
    public boolean setWorkingDirectory(String dir) {
        if (!is_connected) {
            return false;
        }

        try {
            return ftp.changeWorkingDirectory(dir);
        } catch (IOException e) {
        }

        return false;
    }

    /**
     * Change working directory on ftp server to parent directory
     *
     * @return true, if working directory changed
     */
    public boolean setParentDirectory() {
        if (!is_connected) {
            return false;
        }

        try {
            return ftp.changeToParentDirectory();
        } catch (IOException e) {
        }

        return false;
    }

    /**
     * Get parent directory name on ftp server
     *
     * @return parent directory
     */
    public String getParentDirectory() {
        if (!is_connected) {
            return "";
        }

        String w = getWorkingDirectory();
        setParentDirectory();
        String p = getWorkingDirectory();
        setWorkingDirectory(w);

        return p;
    }

    /**
     * Get directory contents on ftp server
     *
     * @param filePath directory
     * @return list of FTPFileInfo structures
     * @throws IOException
     */
    public List<FfpFileInfo> listFiles(String filePath) throws IOException {
        List<FfpFileInfo> fileList = new ArrayList<FfpFileInfo>();

        // Use passive mode to pass firewalls.
        ftp.enterLocalPassiveMode();
        FTPFile[] ftpFiles = ftp.listFiles(filePath);
        int size = (ftpFiles == null) ? 0 : ftpFiles.length;
        for (int i = 0; i < size; i++) {
            FTPFile ftpFile = ftpFiles[i];
            FfpFileInfo fi = new FfpFileInfo();
            fi.setName(ftpFile.getName());
            fi.setSize(ftpFile.getSize());
            fi.setTimestamp(ftpFile.getTimestamp());
            fi.setType(ftpFile.isDirectory());
            fileList.add(fi);
        }

        return fileList;
    }

    /**
     * Get file from ftp server into given output stream
     *
     * @param ftpFileName file name on ftp server
     * @param out         OutputStream
     * @throws IOException
     */
    public void getFile(String ftpFileName, OutputStream out) throws IOException {
        try {
            // Use passive mode to pass firewalls.
            ftp.enterLocalPassiveMode();

            // Get file info.
            FTPFile[] fileInfoArray = ftp.listFiles(ftpFileName);
            if (fileInfoArray == null) {
                throw new FileNotFoundException("File '" + ftpFileName + "' was not found on FTP server.");
            }

            // Check file size.
            FTPFile fileInfo = fileInfoArray[0];
            long size = fileInfo.getSize();
            if (size > Integer.MAX_VALUE) {
                throw new IOException("File '" + ftpFileName + "' is too large.");
            }

            // Download file.
            if (!ftp.retrieveFile(ftpFileName, out)) {
                throw new IOException("Error loading file '" + ftpFileName + "' from FTP server. Check FTP permissions and path.");
            }

            out.flush();

        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException ex) {
                }
            }
        }
    }

    /**
     * Put file on ftp server from given input stream
     *
     * @param ftpFileName file name on ftp server
     * @param in          InputStream
     * @throws IOException
     */
    public void putFile(String ftpFileName, InputStream in) throws IOException {
        try {
            // Use passive mode to pass firewalls.
            ftp.enterLocalPassiveMode();

            if (!ftp.storeFile(ftpFileName, in)) {
                throw new IOException("Can't upload file '" + ftpFileName + "' to FTP server. Check FTP permissions and path.");
            }
        } finally {
            try {
                in.close();
            } catch (IOException ex) {
            }
        }
    }


    public void syncFiles(String host, int port, String user, String password, String filePath, String storePath) throws IOException {
        connect(host, port, user, password, true);
        String hostPath = host.replaceAll("\\.", "");
        OutputStream out = null;
        if (is_connected) {
            List<String> fileList = list(filePath);
            for (String name : fileList) {
                ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
                String fileName = storePath + "/" + hostPath + "/" + name;
                String filePath1 = fileName.substring(0,fileName.lastIndexOf("/"));
                if (StringUtils.isBlank(filePath1)){
                    filePath1 = fileName.substring(0,fileName.lastIndexOf("\\"));
                }
                File file = new File(filePath1);
                if (!file.exists()) {
                    file.mkdirs();
                }
                out = new BufferedOutputStream(new FileOutputStream(fileName));
                getFile(name, out);
            }
        }
        disconnect();
    }

    public static void main(String[] args) throws IOException {
        String host = "172.0.52.144";
        int port = 21;
        String user = "ftpuser";
        String password = "1qaz2wsx";
        String filePath = "/home/test";
        String storePath = "F:\\file";
        FtpUtil ftpUtil = FtpUtil.getFtpUtilInstance(host, port, user, password);
        int i = ftpUtil.recursiveDownloadFile("test1", storePath);
//        FtpUtils ftpUtils = new FtpUtils();
//        ftpUtils.syncFiles(host, port, user, password, filePath, storePath);
    }
}