springboot-ftp

springboot-ftp

代码展示

springboot:2.1.4.RELEASE
java:1.8
ftp在远程局域网linux服务器,调用客户端在win电脑。

依赖

        <dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>3.7.2</version>
        </dependency>

使用hutool

        File file = new File("D:\\host_file.txt");
        Ftp ftp = new Ftp("10.1.1.2", 21, "demo", "1111");
        FTPClient client = ftp.getClient();
        client.setUseEPSVwithIPv4(true);//设置为true 否则可能报 connection refused
        //client.setRemoteVerificationEnabled(false);
        client.enterLocalPassiveMode();//必须开启被动模式
        boolean upload = ftp.upload("/", file.getName(), file);
        System.out.println("upload="+upload);
        ftp.close();

FTPUtils工具类和使用示例

package cn.demo.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Pattern;


@Slf4j
@Component
public class FTPUtils {

    @Value("${cw.ftp.host}")
    private String host = "10.128.1.1";
    @Value("${cw.ftp.username}")
    private String username = "abc";
    @Value("${cw.ftp.password}")
    private String password = "123456";
    @Value("${cw.ftp.port}")
    private int port = 21;
    @Value("${cw.ftp.path}")
    private String path = "./";

    public String getPath() {
        return path;
    }

    /**
     * 示例
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        final FTPUtils ftpUtils = new FTPUtils();

        FTPClient ftpClient = ftpUtils.connectFtp();
        System.out.println(ftpClient.getDataConnectionMode());
        System.out.println(ftpClient.listFiles("zip")[0].getName());

        final List<String> zip = ftpUtils.getFileNameList(ftpClient, "zip");
        System.out.println(zip);

        ftpUtils.closeFtpClient(ftpClient);

     /*   FTPClient ftpClient = ftpUtils.loginFTP();
        final boolean zip = ftpUtils.changeWorkingDirectory(ftpClient,"zip");
        System.out.println(zip);
        //ftpClient.enterRemotePassiveMode();
        ftpClient.enterLocalActiveMode();
        final FTPFile[] ftpFiles = ftpClient.listFiles();
        Arrays.stream(ftpFiles).forEach(System.out::println);

        */

        // final List<String> strings = ftpUtils.showPatternFiles("zip", "a", "txt");
        // System.out.println(strings);
    }

    /**
     * 登陆FTP并获取FTPClient对象
     *
     * @return
     */
    public FTPClient connectFtp() {
        FTPClient ftpClient = null;
        try {
            ftpClient = new FTPClient();
            ftpClient.setConnectTimeout(1000 * 30);//设置连接超时时间
            ftpClient.connect(host, Integer.valueOf(port));// 连接FTP服务器
            ftpClient.login(username, password);// 登陆FTP服务器
            ftpClient.setControlEncoding("UTF-8");// 中文支持
            // 设置文件类型为二进制(如果从FTP下载或上传的文件是压缩文件的时候,不进行该设置可能会导致获取的压缩文件解压失败)
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            //默认模式0
            //模式2,查询文件失败
            ftpClient.enterLocalPassiveMode();//开启被动模式,否则文件上传不成功,也不报错
            ftpClient.setUseEPSVwithIPv4(true);//设置为true 否则可能报 connection refused
            //ftpClient.setRemoteVerificationEnabled(false);
            //模式0,可以查询到文件
            //ftpClient.enterLocalActiveMode();
            //模式3,查询文件失败
            //ftpClient.enterRemotePassiveMode();
            if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
                log.info("连接FTP失败,用户名或密码错误。");
                ftpClient.disconnect();
            } else {
                log.info("FTP连接成功!");
            }
        } catch (Exception e) {
            log.info("登陆FTP失败,请检查FTP相关配置信息是否正确!" + e);
            return null;
        }
        return ftpClient;
    }
    /**
     * 关闭FTP连接
     *
     * @param ftpClient
     */
    public void closeFtpClient(FTPClient ftpClient) {
        if (ftpClient.isConnected()) {
            try {
                ftpClient.disconnect();
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        }
    }

    /**
     * 按前后缀查询文件
     * @param facepic
     * @param prefix
     * @param suffix
     * @return
     */
    public List<String> showPatternFiles(String facepic, String prefix, String suffix) {
        List<String> ret = new ArrayList();
        String fileName = null;
        FTPClient ftpClient = null;
        try {
            ftpClient = connectFtp();
            boolean changeFlag = ftpClient.changeWorkingDirectory(facepic);
            if (!changeFlag) {
                throw new IOException("进入Ftp目录" + facepic + "失败");
            }
            FTPFile[] files = ftpClient.listFiles(getPath());
            for (FTPFile ftpFile : files) {
                fileName = ftpFile.getName();
                if ((!".".equals(fileName)) && (!"..".equals(fileName))) {
                    String regEx = null;
                    if (StringUtils.isNotBlank(prefix)) {
                        regEx = prefix + "*." + suffix;
                    } else {
                        regEx = suffix + "$";
                    }
                    Pattern pattern = Pattern.compile(regEx);
                    if (pattern.matcher(fileName).find()) {
                        ret.add(fileName);
                    }
                }
            }
        } catch (Exception e) {
            log.error("获取文件失败", e);
        } finally {
            if (ftpClient != null) {
                //close(ftpClient);
            }
        }
        return ret;
    }




    /**
     * 从FTP下载文件到本地
     *
     */
    public String downloadFile(FTPClient ftpClient, String remotePath, String fileName, String downloadPath) {
        InputStream is = null;
        FileOutputStream fos = null;
        final File targetFile = new File(downloadPath + File.separator + fileName);
        try {
            is = ftpClient.retrieveFileStream(remotePath+"/"+ fileName);// 获取ftp上的文件

            if(!targetFile.getParentFile().exists()){
                targetFile.getParentFile().mkdirs();
            }
            fos = new FileOutputStream(new File(downloadPath+File.separator+fileName));
            // 文件读取方式一
            int i;
            byte[] bytes = new byte[1024];
            while ((i = is.read(bytes)) != -1) {
                fos.write(bytes, 0, i);
            }
            // 文件读取方式二
            //ftpClient.retrieveFile(fileName, new FileOutputStream(new File(downloadPath)));
            ftpClient.completePendingCommand();
            log.info("FTP文件下载成功!");
        } catch (Exception e) {
            log.error("FTP文件下载失败!",e);
        } finally {
            try {
                if (fos != null) {
                    fos.close();
                }
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                log.error("下载流关闭失败" , e);
            }
        }
        return targetFile.getAbsolutePath();
    }


    /**
     * 上传文件
     *
     * @param serviceDec     ftp服务保存地址
     * @param fileName       上传到ftp的文件名
     * @param originfilename 待上传文件的名称(绝对地址) *
     * @return
     */
    public boolean uploadFile(FTPClient ftpClient, String serviceDec, String fileName, String originfilename) {
        log.info("开始上传文件");
        try (InputStream input = new FileInputStream(new File(originfilename))) {
            return uploadFile(ftpClient, serviceDec, fileName, input);
        } catch (FileNotFoundException e) {
            log.error("文件上传失败" + e);
        } catch (IOException e) {
            log.error("文件上传失败" + e);
        }
        return false;
    }

    /**
     * 上传文件
     *
     * @param serviceDec  ftp服务保存地址
     * @param fileName    上传到ftp的文件名
     * @param inputStream 输入文件流
     * @return
     */
    private boolean uploadFile(FTPClient ftpClient, String serviceDec, String fileName, InputStream inputStream) {
        try {
            log.info("开始上传文件");
            ftpClient.setFileType(ftpClient.BINARY_FILE_TYPE);
            createDirecroty(ftpClient, serviceDec);
            ftpClient.makeDirectory(serviceDec);
            ftpClient.changeWorkingDirectory(serviceDec);
            ftpClient.storeFile(fileName, inputStream);
            inputStream.close();
            ftpClient.logout();
            log.info("上传文件成功");
        } catch (Exception e) {
            log.error("上传文件失败" + e);
        } finally {
            try {
                if (ftpClient.isConnected()) {
                    ftpClient.disconnect();
                }
                if (null != inputStream) {
                    inputStream.close();
                }
            } catch (IOException e) {
                log.error("上传文件失败" + e);
                return false;
            }
        }
        return true;
    }


    //改变目录路径
    private boolean changeWorkingDirectory(FTPClient ftpClient, String directory) {
        boolean flag = true;
        try {
            flag = ftpClient.changeWorkingDirectory(directory);
            if (flag) {
                log.info("进入文件夹" + directory + " 成功!");

            } else {
                log.info("进入文件夹" + directory + " 失败!开始创建文件夹");
            }
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
        return flag;
    }

    //创建多层目录文件,如果有ftp服务器已存在该文件,则不创建,如果无,则创建
    private boolean createDirecroty(FTPClient ftpClient, String remote) throws IOException {
        boolean success = true;
        String directory = remote + "/";
        // 如果远程目录不存在,则递归创建远程服务器目录
        if (!directory.equalsIgnoreCase("/") && !changeWorkingDirectory(ftpClient, new String(directory))) {
            int start = 0;
            int end = 0;
            if (directory.startsWith("/")) {
                start = 1;
            } else {
                start = 0;
            }
            end = directory.indexOf("/", start);
            String path = "";
            String paths = "";
            while (true) {
                String subDirectory = new String(remote.substring(start, end).getBytes("GBK"), "iso-8859-1");
                path = path + "/" + subDirectory;
                if (!existFile(ftpClient, path)) {
                    if (makeDirectory(ftpClient, subDirectory)) {
                        changeWorkingDirectory(ftpClient, subDirectory);
                    } else {
                        log.info("创建目录[" + subDirectory + "]失败");
                        changeWorkingDirectory(ftpClient, subDirectory);
                    }
                } else {
                    changeWorkingDirectory(ftpClient, subDirectory);
                }

                paths = paths + "/" + subDirectory;
                start = end + 1;
                end = directory.indexOf("/", start);
                // 检查所有目录是否创建完毕
                if (end <= start) {
                    break;
                }
            }
        }
        return success;
    }

    //判断ftp服务器文件是否存在
    private boolean existFile(FTPClient ftpClient, String path) throws IOException {
        boolean flag = false;
        FTPFile[] ftpFileArr = ftpClient.listFiles(path);
        if (ftpFileArr.length > 0) {
            flag = true;
        }
        return flag;
    }

    //创建目录
    private boolean makeDirectory(FTPClient ftpClient, String dir) {
        boolean flag = true;
        try {
            flag = ftpClient.makeDirectory(dir);
            if (flag) {
                log.info("创建文件夹" + dir + " 成功!");

            } else {
                log.info("创建文件夹" + dir + " 失败!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 获取FTP某一特定目录下的所有文件名称
     *
     * @param ftpClient  已经登陆成功的FTPClient
     * @param ftpDirPath FTP上的目标文件路径
     */
    public List<String> getFileNameList(FTPClient ftpClient, String ftpDirPath) {
        List<String> list = new ArrayList();
        try {

            // 通过提供的文件路径获取FTPFile对象列表
            FTPFile[] files = ftpClient.listFiles(ftpDirPath);
            // 遍历文件列表,打印出文件名称
            for (int i = 0; i < files.length; i++) {
                FTPFile ftpFile = files[i];
                // 此处只打印文件,未遍历子目录(如果需要遍历,加上递归逻辑即可)
                if (ftpFile.isFile()) {
//                        log.info(ftpDirPath + ftpFile.getName());
                    list.add(ftpFile.getName());
                }
            }
        } catch (IOException e) {
            log.error("错误" + e);
        }
        return list;
    }

    /**
     * 获取到服务器文件夹里面最新创建的文件名称
     *
     * @param ftpDirPath 文件路径
     * @param ftpClient  ftp的连接
     * @return fileName
     */
    public String getNewFile(FTPClient ftpClient, String ftpDirPath) throws Exception {

        // 通过提供的文件路径获取FTPFile对象列表
        FTPFile[] files = ftpClient.listFiles(ftpDirPath);
        if (files == null) {
            throw new Exception("文件数组为空");
        }
        Arrays.sort(files, new Comparator<FTPFile>() {
            @Override
            public int compare(FTPFile f1, FTPFile f2) {
                return f1.getTimestamp().compareTo(f2.getTimestamp());
            }

            public boolean equals(Object obj) {
                return true;
            }
        });
        return ftpDirPath + "/" + files[files.length - 1].getName();

    }
}

打印日志:

11:28:26.737 [main] INFO cn.cloudwalk.util.FTPUtils - FTP连接成功!
0
a.txt
[a.txt]

Process finished with exit code 0

端口模式

  • 默认模式0,可以查询到文件(我试了其他模式,只有这个能读取并下载文件列表)
    ftpClient.enterLocalActiveMode();
    设置当前数据连接模式为ACTIVE_LOCAL_DATA_CONNECTION_MODE。没有与FTP服务器进行通信,但是这将导致以后所有的数据传输都需要FTP服务器连接到客户端的数据端口。此外,为了适应不同平台上套接字实现之间的差异,该方法导致客户端在每次数据传输之前发出一个PORT命令。

  • 模式2,查询文件失败
    ftpClient.enterLocalPassiveMode();//开启被动模式,否则文件上传不成功,也不报错
    将当前数据连接模式设置为PASSIVE_LOCAL_DATA_CONNECTION_MODE。此方法仅用于客户端和服务器之间的数据传输。这种方法会在打开每个数据连接之前向服务器发出一个PASV(或EPSV)命令,告诉服务器打开一个数据端口,客户端将连接到该端口进行数据传输。FTPClient将保持在PASSIVE_LOCAL_DATA_CONNECTION_MODE中,直到通过调用enterLocalActiveMode()等其他方法改变该模式。
    注意:当前调用任何连接方法都会将模式重置为ACTIVE_LOCAL_DATA_CONNECTION_MODE。

  • 模式3,查询文件失败
    ftpClient.enterRemotePassiveMode();
    设置当前数据连接方式为PASSIVE_REMOTE_DATA_CONNECTION_MODE。此方法仅适用于服务器之间的数据传输。该方法向服务器发出一个PASV命令,告诉它打开一个数据端口,活动服务器将连接到该端口进行数据传输。您必须在每个服务器之间的传输尝试之前调用此方法。FTPClient不会自动继续发出PASV命令。如果希望返回到正常的数据连接模式,还必须记住调用enterLocalActiveMode()。
    返回:
    如果成功完成则为True,否则为false。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
springboot整合ftp可以通过引入相关的依赖和配置来实现。首先,在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-net</artifactId> <version>3.6</version> </dependency> ``` 然后,在application.properties或application.yml文件中配置ftp连接信息,例如: ``` ftp.host=ftp.example.com ftp.port=21 ftp.username=admin ftp.password=123456 ``` 接下来,创建一个FTP工具类,用于连接和操作ftp服务器。在该类中,可以使用`FTPClient`类进行ftp操作,例如上传文件、下载文件等。示例如下: ```java import org.apache.commons.net.ftp.FTPClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class FTPUtil { @Value("${ftp.host}") private String host; @Value("${ftp.port}") private int port; @Value("${ftp.username}") private String username; @Value("${ftp.password}") private String password; public void uploadFile(String remotePath, String fileName, File file) throws IOException { FTPClient ftpClient = new FTPClient(); try { ftpClient.connect(host, port); ftpClient.login(username, password); ftpClient.setFileType(FTP.BINARY_FILE_TYPE); ftpClient.enterLocalPassiveMode(); ftpClient.changeWorkingDirectory(remotePath); try (InputStream inputStream = new FileInputStream(file)) { ftpClient.storeFile(fileName, inputStream); } } finally { if (ftpClient.isConnected()) { ftpClient.disconnect(); } } } // 其他ftp操作方法... } ``` 最后,可以在其他地方注入`FTPUtil`类,并调用其方法来实现ftp操作。例如: ```java @Service public class MyService { private final FTPUtil ftpUtil; @Autowired public MyService(FTPUtil ftpUtil) { this.ftpUtil = ftpUtil; } public void uploadFile() { // 上传文件 File file = new File("path/to/file"); try { ftpUtil.uploadFile("remote/path", "filename.txt", file); } catch (IOException e) { e.printStackTrace(); } } // 其他方法... } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值