最近收到一个需求要从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工具也能下载,说明服务端是没问题的,这时一般会看源码去分析,但往往事情比较急没那个时间分析,不如换个思路去做。