spring boot 从ftp下载文件 commons-net 下载问题

最近收到一个需求要从ftp读取文件,再调用三方接口发送给三方。随手找了一下,spring boot都是在用commons-net包来下载pdf文件。于是很自然的写了代码去做,结果发现commons-net有时候有何不好用。直接上代码:

    /**
     * 测试上传PDF
     * @return 成功失败
     */
    public String testPdf() {
        logger.info("开始上传PDF");
        //1.查询数据----------
        try {
            String filePath = "ftp://192.168.1.200/PDF/2024/08/06/141554979.pdf";
            String path = "/PDF/2024/08/06/";
            String name = "141554979.pdf";

            URL url1 = new URL(filePath);
            String server = url1.getHost();
            //ftp 读取文件
            FTPClient ftpClient = new FTPClient();
            ftpClient.connect(server, Integer.parseInt(port));
            ftpClient.login(user, pass);
            ftpClient.enterLocalPassiveMode();
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            ftpClient.setControlEncoding("GBK");

            //是否成功登录服务器
            int replyCode = ftpClient.getReplyCode();
            if (FTPReply.isPositiveCompletion(replyCode)) {
                logger.info("ftp服务器登录成功");
                logger.info("文件路径为{}",path);
                ftpClient.changeWorkingDirectory(path);
                logger.info("成功切换路径");
                FTPFile[] ftpFiles = ftpClient.listFiles();

                for (FTPFile file : ftpFiles) {
                    logger.info("文件名为{}",file.getName());
                    if (name.equalsIgnoreCase(file.getName())) {
                        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                        // 读取文件
                        if (ftpClient.retrieveFile(file.getName(), outputStream)) {
                            // 获取文件内容类型
                            byte[] fileBytes = outputStream.toByteArray();
                            String content = Base64.getEncoder().encodeToString(fileBytes);
                            logger.info("ftp文件下载成功{}",content);
                            return "文件下载成功";
                        } else {
                            logger.info("ftp文件下载失败2{}",filePath);
                        }
                        outputStream.flush();
                        outputStream.close();
                        if (null != ftpClient && ftpClient.isConnected()) {
                            ftpClient.logout();
                            ftpClient.disconnect();
                        }
                    }
                }
            } else {
                logger.info("ftp服务器登录失败");

            }

            if (null != ftpClient && ftpClient.isConnected()) {
                ftpClient.logout();
                ftpClient.disconnect();
            }

        } catch (Exception e) {
            logger.error("上传PDF异常",e);
        }
        logger.info("结束上传PDF");
        return "1";
    }

问题出在ftpClient.retrieveFile(file.getName(), outputStream)这一行,非常的奇怪,我在测试环境时OK可用的,正式环境就是用不了,文件列表都获取到了,下载却一直失败。搜索了一下都说的是ftp服务那边的问题,什么权限、用户之类。但正式环境上我用ftp工具直接登录上去是可以下载文件的,直觉告诉我还是代码问题。我简单看了下源码也没看出啥问题,现场催促的又急,一气之下直接用命令去下载好了。

命令下载代码

 public String testPdf2() {
        logger.info("开始上传PDF");
        //1.查询数据----------
        try {
            String filePath = "ftp://192.168.1.200/LISPDF/2024/08/06/梅佑泽_141554979.pdf";
            URL url1 = new URL(filePath);
            String server = url1.getHost();
            String path = url1.getPath();
//            String path = "/test/mail_frame11.pdf";
            try {
                // Connect to the FTP server
                Socket socket = new Socket(server, Integer.parseInt(port));
                InputStream inputStream = socket.getInputStream();
                OutputStream outputStream = socket.getOutputStream();
                String response = "";

                // Login to the FTP server
                sendCommand(outputStream, "USER " + user);
                response = readResponse(inputStream);
                logger.info("USER回复{}",response);
                sendCommand(outputStream, "PASS " + pass);
                response = readResponse(inputStream);
                response = readResponse(inputStream);
                logger.info("PASS回复{}",response);
                // Change to binary mode
                sendCommand(outputStream, "TYPE I");
                response = readResponse(inputStream);
                logger.info("TYPE I回复{}",response);
                // Set up data connection for file transfer
                sendCommand(outputStream, "PASV");
                response = readResponse(inputStream);
                logger.info("PASV回复{}",response);
                String[] parts = response.split("\\(")[1].split("\\)")[0].split(",");
                String dataServer = parts[0] + "." + parts[1] + "." + parts[2] + "." + parts[3];
                int dataPort = (Integer.parseInt(parts[4]) * 256) + Integer.parseInt(parts[5]);

                Socket dataSocket = new Socket(dataServer, dataPort);
                InputStream dataInputStream = dataSocket.getInputStream();

                // Download the file
                sendCommand(outputStream, "RETR " + path);
                response = readResponse(inputStream);
                logger.info("RETR回复{}",response);

                try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
                    byte[] buffer = new byte[1024];
                    int bytesRead;
                    while ((bytesRead = dataInputStream.read(buffer)) != -1) {
                        byteArrayOutputStream.write(buffer, 0, bytesRead);
                    }
                    // 获取文件内容类型
                    byte[] fileBytes = byteArrayOutputStream.toByteArray();
                    String content = Base64.getEncoder().encodeToString(fileBytes);
                    logger.info("文件转base64结果为{}",content);
                }

                // Close connections
                dataSocket.close();
                socket.close();
                logger.info("下载pdf成功");
                return "下载pdf成功";
            } catch (Exception e) {
                logger.error("22上传PDF异常",e);
            }

        } catch (Exception e) {
            logger.error("上传PDF异常",e);
        }
        logger.info("结束上传PDF");
        return "1";
    }

    private static void sendCommand(OutputStream outputStream, String command) throws Exception {
        outputStream.write((command + "\r\n").getBytes("GBK"));
        outputStream.flush();
    }

    private static String readResponse(InputStream inputStream) throws Exception {
        StringBuilder response = new StringBuilder();
        int ch;
        while ((ch = inputStream.read()) != -1) {
            response.append((char) ch);
            if (response.toString().endsWith("\r\n")) {
                break;
            }
        }
        return response.toString();
    }

果然命令模式下载还是OJ8K的,问题搞定。

总结:有时候一些常用的包不一定就是稳定可靠的,有些场景出问题又要求快速解决时可以先考虑换个方式做。像我这里测试环境怎么测都是OK的,正式环境用ftp工具也能下载,说明服务端是没问题的,这时一般会看源码去分析,但往往事情比较急没那个时间分析,不如换个思路去做。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值