java
复制代码
package com.skybird.iot.addons.flow.flowCreator.web.nodes.fileManage.backend;
import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.skybird.commons.mongo.DocuLib;
import com.skybird.iot.addons.flow.flowCreator.backend.base.service.FlowNodeRunBaseService;
import com.skybird.iot.addons.flow.flowCreator.backend.dto.FlowRunDataDto;
import com.skybird.iot.addons.flow.flowCreator.backend.util.FlowFtpUtils;
import com.skybird.iot.addons.flow.flowCreator.backend.util.FlowProtocolAccessLogUtil;
import com.skybird.iot.addons.flow.flowCreator.web.nodes.fileManage.backend.service.FlowOssService;
import jakarta.annotation.Resource;
import org.bson.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class FlowFtpDownloadService extends FlowNodeRunBaseService {
private static final Logger LOGGER =
LoggerFactory.getLogger(FlowFtpDownloadService.class.getName());
@Resource
FlowFolderJudgmentReadService flowFolderJudgmentReadService;
@Resource
FlowOssService flowOssService;
@Override
public String[] getComponentKey() {
return new String[]{"ftp_download"};
}
@Override
public void run(FlowRunDataDto flowRunDataDto) throws Exception {
Document nodeConfig = flowRunDataDto.getNodeConfig();
String ipRow = String.valueOf(flowRunDataDto.getFieldValue(DocuLib.getDocu(nodeConfig, "ip")));
String username = String.valueOf(flowRunDataDto.getFieldValue(DocuLib.getDocu(nodeConfig, "username")));
String password = String.valueOf(flowRunDataDto.getFieldValue(DocuLib.getDocu(nodeConfig, "password")));
String fileName = String.valueOf(flowRunDataDto.getFieldValue(DocuLib.getDocu(nodeConfig, "fileName")));
String localFilePath = String.valueOf(flowRunDataDto.getFieldValue(DocuLib.getDocu(nodeConfig, "localFilePath")));
String directoryPath = String.valueOf(flowRunDataDto.getFieldValue(DocuLib.getDocu(nodeConfig, "directoryPath")));
String timeoutMillis1 = String.valueOf(flowRunDataDto.getFieldValue(DocuLib.getDocu(nodeConfig, "timeoutMillis")));
String keepAliveTimeout1 = String.valueOf(flowRunDataDto.getFieldValue(DocuLib.getDocu(nodeConfig, "keepAliveTimeout")));
String dataTimeout1 = String.valueOf(flowRunDataDto.getFieldValue(DocuLib.getDocu(nodeConfig, "dataTimeout")));
String ports = String.valueOf(flowRunDataDto.getFieldValue(DocuLib.getDocu(nodeConfig, "port")));
int port = 21;
int keepAliveTimeout = 6;//默认6秒
int dataTimeout = 5000;//默认5秒
if (StrUtil.isEmpty(timeoutMillis1) || timeoutMillis1.startsWith("Document{")) {
timeoutMillis1 = "1000";
}
if (StrUtil.isNotBlank(keepAliveTimeout1) && !keepAliveTimeout1.startsWith("Document{")) {
keepAliveTimeout = Integer.parseInt(keepAliveTimeout1);
}
if (StrUtil.isNotBlank(dataTimeout1) && !dataTimeout1.startsWith("Document{")) {
dataTimeout = Integer.parseInt(dataTimeout1);
}
if (StrUtil.isNotBlank(ports) && !ports.startsWith("Document{")) {
port = Integer.parseInt(ports);
}
Integer timeoutMillis = Integer.parseInt(timeoutMillis1);//ftp ip校验超时时间毫秒
String ftpType = DocuLib.getStr(nodeConfig, "ftpType.id");
Document result = DocuLib.newDoc();
if (FlowFtpUtils.pingHost(ipRow, timeoutMillis)) {
if (StrUtil.equals(ftpType, "1")) {
Document dto = FlowFtpUtils.downloadFileByName(username, password, ipRow, port, localFilePath, fileName, directoryPath, keepAliveTimeout, dataTimeout);
result.putAll(dto);
} else if (StrUtil.equals(ftpType, "2")) {
Document dto = FlowFtpUtils.vagueDownloadFile(username, password, ipRow, port, localFilePath, fileName, directoryPath, keepAliveTimeout, dataTimeout);
result.putAll(dto);
} else if (StrUtil.equals(ftpType, "4")) {
Document dto = FlowFtpUtils.listDownloadGetLatestFile(username, password, ipRow, port, localFilePath, directoryPath, keepAliveTimeout, dataTimeout);
result.putAll(dto);
} else if (StrUtil.equals(ftpType, "5")) {
Object downloadedListObj = flowRunDataDto.getFieldValue(DocuLib.getDocu(nodeConfig, "downloadedList"));
List<String> downloadedList = null;
if (downloadedListObj instanceof List) {
try {
downloadedList = ((List<?>) downloadedListObj).stream()
.map(Object::toString)
.toList();
} catch (Exception e) {
result.append("message", "过滤已下载的文件请传List<String>");
}
}
Document dto = FlowFtpUtils.listDownloadGetAllLatestDateFiles(username, password, ipRow, port, localFilePath, directoryPath, keepAliveTimeout, dataTimeout,downloadedList);
result.putAll(dto);
} else if (StrUtil.equals(ftpType, "6")) {
Document dto = FlowFtpUtils.downloadAllFile(username, password, ipRow, port, localFilePath, directoryPath, keepAliveTimeout, dataTimeout);
result.putAll(dto);
} else {
Document dto = FlowFtpUtils.listDownloadGetFirstFile(username, password, ipRow, port, localFilePath, directoryPath, keepAliveTimeout, dataTimeout);
result.putAll(dto);
}
} else {
result.append("message", "请检查网络情况,IP未通!");
}
flowRunDataDto.nodeValueAppend(new Document().append("result", result));
FlowProtocolAccessLogUtil.addProtocolReadLog(nodeConfig, result);
}
@Override
public void unRegister() {
}
}
java
复制代码
package com.skybird.iot.addons.flow.flowCreator.backend.util;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.ftp.Ftp;
import cn.hutool.extra.ftp.FtpConfig;
import cn.hutool.extra.ftp.FtpMode;
import com.skybird.commons.mongo.DocuLib;
import com.skybird.commons.utils.DigestLib;
import com.skybird.commons.utils.StreamUtils;
import java.net.InetAddress;
import java.time.LocalDate;
import java.time.ZoneId;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.nio.charset.Charset;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.bson.Document;
public class FlowFtpUtils {
private static Map<String, Ftp> ftpServerMap = new ConcurrentHashMap();
/**
* 判断IP地址是否可达
*
* @param ip
* @param timeoutMillis 超时时间毫秒
* @return
*/
public static boolean isHostReachable(String ip, int timeoutMillis) {
try {
return InetAddress.getByName(ip).isReachable(timeoutMillis);
} catch (Exception e) {
return false;
}
}
/**
* 判断IP地址是否可达 ping方式
*
* @param ipOrHost
* @param timeoutMs
* @return
*/
public static boolean pingHost(String ipOrHost, int timeoutMs) {
String command = System.getProperty("os.name").toLowerCase().contains("win")
? "ping -n 1 -w " + timeoutMs + " " + ipOrHost
: "ping -c 1 -W " + (timeoutMs / 1000) + " " + ipOrHost;
String result = RuntimeUtil.execForStr(command);
return result.contains("TTL=") || result.contains("ttl=");
}
/***
* 获取ftp连接(不开启复用)
*
* @param ftpConfig
* @return
*/
public static Ftp getFtpClient(Document ftpConfig) {
return getFtpClient(ftpConfig, false);
}
/***
* 获取ftp连接
*
* @param ftpConfig
* @param reUse 需要留意 这里会有超时执行的等待时间损耗 等待超时后才会进行初始化重连(频率高的操作不能开启)
* @return
*/
public static Ftp getFtpClient(Document ftpConfig, boolean reUse) {
String host = DocuLib.getStr(ftpConfig, "ip");
int port = DocuLib.getInt(ftpConfig, "port");
if (StrUtil.isEmpty(host) || port <= 0) {
return null;
}
String username = DocuLib.getStr(ftpConfig, "username");
String password = DocuLib.getStr(ftpConfig, "password");
String modeValue = DocuLib.getStr(ftpConfig, "connType.id");
String encoding = DocuLib.getStr(ftpConfig, "encoding.id");
// 如果有复用连接的设置 从内存里取回连接实例 尝试重连激活即可
String key;
if (reUse) {
key = DigestLib.md5Hex(host + port + username + password);
Ftp ftp = ftpServerMap.get(key);
if (Objects.nonNull(ftp)) {
ftp.reconnectIfTimeout();
return ftp;
}
}
Charset charset =
StreamUtils.mayIf(
StrUtil.isNotEmpty(encoding),
() -> CharsetUtil.charset(encoding),
() -> CharsetUtil.CHARSET_UTF_8);
int conn_timeout = DocuLib.getInt(ftpConfig, "conn_timeout");
if (conn_timeout < 60000) {
conn_timeout = 60000;
}
FtpConfig config =
FtpConfig.create()
.setCharset(charset)
.setConnectionTimeout(conn_timeout)
.setHost(host)
.setPort(port);
if (StrUtil.isNotEmpty(username)) {
config.setUser(username);
}
if (StrUtil.isNotEmpty(password)) {
config.setPassword(password);
}
FtpMode mode = FtpMode.Passive;
if (StrUtil.equalsIgnoreCase(modeValue, "active")) {
mode = FtpMode.Active;
}
Ftp ftp = new Ftp(config, mode);
return ftp;
}
/**
* 从FTP服务器下载文件
*
* @param userName 用户名
* @param password 密码
* @param ip ip地址
* @param localFilePath 本地保存路径
* @param fileName 文件名
*/
public static Document downloadFile(String userName, String password, String ip, String localFilePath, String fileName) {
String ftpUrl = StrUtil.format("ftp://{}:{}@{}/{}", userName, password, ip, fileName);
File localDir = new File(localFilePath);
try {
// 确保本地路径存在
if (!localDir.exists()) {
if (!localDir.mkdirs()) {
return DocuLib.newDoc("message", "无法创建本地目录: " + localFilePath);
}
}
// 确保本地路径以斜杠结尾
if (!localFilePath.endsWith("/") && !localFilePath.endsWith("\\")) {
localFilePath += File.separator;
}
String key = localFilePath + generateHexId() + "-" + fileName;
File localFile = new File(key);
URL url = new URL(ftpUrl);
try (ReadableByteChannel rbc = Channels.newChannel(url.openStream());
FileOutputStream fos = new FileOutputStream(localFile);
WritableByteChannel wbc = fos.getChannel()) {
ByteBuffer buffer = ByteBuffer.allocate(2048);
while (rbc.read(buffer) != -1) {
buffer.flip();
wbc.write(buffer);
buffer.clear();
}
} catch (IOException e) {
e.printStackTrace();
throw e;
}
return DocuLib.newDoc("filePath", key);
} catch (MalformedURLException e) {
return DocuLib.newDoc("message", "无效的URL格式: " + e.getMessage());
} catch (FileNotFoundException e) {
return DocuLib.newDoc("message", "文件未找到: " + e.getMessage());
} catch (IOException e) {
return DocuLib.newDoc("message", "文件下载失败: " + e.getMessage());
} catch (Exception e) {
return DocuLib.newDoc("message", "下载异常: " + e.getMessage());
}
}
/**
* ftp根据文件目录获取相同文件名的文件下载到本地
*
* @param userName 用户名
* @param password 密码
* @param ip ip地址
* @param localFilePath 本地保存路径
* @param fileName 文件名
* @param directoryPath 文件目录,如果为空则默认根目录
* @param keepAliveTimeout 控制连接的KeepAlive超时时间
* @param dataTimeout 数据传输的超时时间
* @return 下载文件的本地路径
*/
public static Document downloadFileByName(String userName, String password, String ip, int port, String localFilePath, String fileName, String directoryPath, int keepAliveTimeout, int dataTimeout) {
FTPClient ftpClient = new FTPClient();
try {
// 连接到 FTP 服务器
ftpClient.connect(ip, port);
ftpClient.setControlEncoding("UTF-8"); // 设置控制连接编码
ftpClient.setAutodetectUTF8(true); // 自动检测UTF-8编码
ftpClient.login(userName, password);
ftpClient.enterLocalPassiveMode();//被动模式
//设置文件传输模式为二进制模式
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
//设置控制连接的KeepAlive超时时间单位(秒),作用:长时间文件传输过程中保持控制连接活跃,防止被服务器断开
ftpClient.setControlKeepAliveTimeout(keepAliveTimeout);
//设置数据传输的超时时间(毫秒)
ftpClient.setDataTimeout(dataTimeout);
directoryPath = new String(directoryPath.getBytes("UTF-8"), "ISO-8859-1");
// 如果 directoryPath 不为空,则切换到指定目录
if (directoryPath != null && !directoryPath.trim().isEmpty()) {
if (!ftpClient.changeWorkingDirectory(directoryPath)) {
return DocuLib.newDoc("message", "找不到目录: " + directoryPath);
}
}
// 确保本地路径以斜杠结尾
if (!localFilePath.endsWith("/") && !localFilePath.endsWith("\\")) {
localFilePath += File.separator;
}
// 获取目录下的文件列表
FTPFile[] files = ftpClient.listFiles();
if (files != null && files.length > 0) {
for (FTPFile file : files) {
if (file.isFile() && file.getName().equals(fileName)) {
String remoteFileName = file.getName();
String localFileName = localFilePath + generateHexId() + "-" + remoteFileName;
File localFile = new File(localFileName);
// 处理中文文件名编码
String encodedFileName = new String(remoteFileName.getBytes("UTF-8"), "ISO-8859-1");
// 下载文件到本地
try (FileOutputStream fos = new FileOutputStream(localFile)) {
InputStream inputStream = ftpClient.retrieveFileStream(encodedFileName);
if (inputStream == null) {
// 检查FTP响应代码以获取更多信息
int replyCode = ftpClient.getReplyCode();
String replyString = ftpClient.getReplyString();
return DocuLib.newDoc("message", "无法获取文件流,FTP响应码: " + replyCode + ", 信息: " + replyString);
}
ReadableByteChannel rbc = Channels.newChannel(inputStream);
ByteBuffer buffer = ByteBuffer.allocate(2048);
while (rbc.read(buffer) != -1) {
buffer.flip();
fos.write(buffer.array(), 0, buffer.limit());
buffer.clear();
}
// 完成文件传输
boolean complete = ftpClient.completePendingCommand();
if (complete) {
Document dto = DocuLib.newDoc("filePath", localFileName);
// 获取文件的最后修改时间
ZonedDateTime zonedDateTime = file.getTimestamp().toInstant().atZone(ZoneId.systemDefault());
LocalDateTime lastModifiedTime = zonedDateTime.toLocalDateTime();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = lastModifiedTime.format(formatter);
dto.put("updateTime", formattedDateTime);
return dto;
} else {
return DocuLib.newDoc("message", "下载文件失败: " + remoteFileName);
}
} catch (IOException e) {
return DocuLib.newDoc("message", "下载文件时发生错误: " + e.getMessage());
}
}
}
}
return DocuLib.newDoc("message", "在目录中找不到文件名 " + fileName + " 的文件: " + (StrUtil.isNotEmpty(directoryPath) ? directoryPath : "根目录"));
} catch (IOException e) {
e.printStackTrace();
return DocuLib.newDoc("message", e.getMessage());
} finally {
try {
if (ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 从本地上传文件到FTP服务器指定目录
*
* @param userName 用户名
* @param password 密码
* @param ip ip地址
* @param port 端口号
* @param localFilePath 本地文件完整路径
* @param fileName 上传后的文件名(可包含路径)
* @param trailerLabel 添加尾标内容,不为空则在文件最后面添加这个内容
* @param format 编码格式
* @return 上传结果
*/
public static Document uploadFileToDirectory(String userName, String password, String ip, int port,
String localFilePath, String fileName, String trailerLabel, String format) {
FTPClient ftpClient = new FTPClient();
File processedFile = null;
File localFile = new File(localFilePath);
try {
// 连接到 FTP 服务器
ftpClient.connect(ip, port);
int connectReply = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(connectReply)) {
return DocuLib.newDoc("message", "连接FTP服务器失败,响应码: " + connectReply);
}
boolean loginSuccess = ftpClient.login(userName, password);
if (!loginSuccess) {
return DocuLib.newDoc("message", "FTP登录失败: " + ftpClient.getReplyString());
}
ftpClient.enterLocalPassiveMode(); // 被动模式
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); // 设置传输模式为二进制
// 确保在根目录开始
ftpClient.changeWorkingDirectory("/");
if (!localFile.exists()) {
return DocuLib.newDoc("message", "本地文件不存在: " + localFilePath);
}
// 如果trailerLabel不为空,则需要先在本地文件末尾添加内容
processedFile = localFile;
if (trailerLabel != null && !trailerLabel.isEmpty()) {
try {
processedFile = appendTrailerToFile(localFile, trailerLabel, format);
} catch (IOException e) {
// 清理临时文件
if (!processedFile.equals(localFile)) {
try {
processedFile.delete();
} catch (Exception deleteEx) {
System.err.println("清理临时文件失败: " + deleteEx.getMessage());
}
}
return DocuLib.newDoc("message", "添加尾标内容时发生错误: " + e.getMessage() + ", 文件路径: " + localFilePath);
}
}
// 标准化文件名中的路径分隔符
fileName = fileName.replace("\\", "/");
String targetFileName = fileName;
String remoteDir = null;
// 如果fileName包含路径,先创建远程目录结构
if (fileName.contains("/")) {
// 提取远程目录路径
int lastSlashIndex = fileName.lastIndexOf('/');
if (lastSlashIndex > 0) { // 确保不是根目录下的文件
remoteDir = fileName.substring(0, lastSlashIndex);
String actualFileName = fileName.substring(lastSlashIndex + 1);
// 切换到目标目录
if (!ftpClient.changeWorkingDirectory(remoteDir)) {
// 目录切换失败,尝试创建目录结构
boolean dirCreated = false;
try {
dirCreated = createRemoteDirectory(ftpClient, remoteDir);
} catch (IOException e) {
// 清理临时文件
if (!processedFile.equals(localFile)) {
try {
processedFile.delete();
} catch (Exception deleteEx) {
System.err.println("清理临时文件失败: " + deleteEx.getMessage());
}
}
return DocuLib.newDoc("message", "创建远程目录时发生错误: " + e.getMessage() + ", 目标目录: " + remoteDir);
}
if (!dirCreated) {
// 清理临时文件
if (!processedFile.equals(localFile)) {
try {
processedFile.delete();
} catch (Exception deleteEx) {
System.err.println("清理临时文件失败: " + deleteEx.getMessage());
}
}
return DocuLib.newDoc("message", "无法访问或创建远程目录: " + remoteDir);
}
// 再次尝试切换到目标目录
if (!ftpClient.changeWorkingDirectory(remoteDir)) {
// 清理临时文件
if (!processedFile.equals(localFile)) {
try {
processedFile.delete();
} catch (Exception deleteEx) {
System.err.println("清理临时文件失败: " + deleteEx.getMessage());
}
}
return DocuLib.newDoc("message", "无法切换到目标目录: " + remoteDir);
}
}
targetFileName = actualFileName;
}
}
try (InputStream inputStream = new FileInputStream(processedFile)) {
// 直接上传文件,FTP会自动覆盖已存在的文件
boolean done = ftpClient.storeFile(targetFileName, inputStream);
if (done) {
// 清理临时文件
if (!processedFile.equals(localFile)) {
try {
processedFile.delete();
} catch (Exception deleteEx) {
System.err.println("清理临时文件失败: " + deleteEx.getMessage());
}
}
return DocuLib.newDoc("check", true);
} else {
// 清理临时文件
if (!processedFile.equals(localFile)) {
try {
processedFile.delete();
} catch (Exception deleteEx) {
System.err.println("清理临时文件失败: " + deleteEx.getMessage());
}
}
// 提供具体的FTP错误信息
int replyCode = ftpClient.getReplyCode();
String replyString = ftpClient.getReplyString();
return DocuLib.newDoc("message", "文件上传失败: " + replyString + " (响应码: " + replyCode + ")" +
", 当前目录: " + getCurrentDirectory(ftpClient) + ", 目标文件: " + targetFileName);
}
} catch (IOException e) {
// 清理临时文件
if (!processedFile.equals(localFile)) {
try {
processedFile.delete();
} catch (Exception deleteEx) {
System.err.println("清理临时文件失败: " + deleteEx.getMessage());
}
}
return DocuLib.newDoc("message", "上传文件时发生I/O错误: " + e.getMessage() +
", 本地文件: " + processedFile.getAbsolutePath() + ", 目标文件: " + targetFileName);
}
} catch (IOException e) {
return DocuLib.newDoc("message", "连接FTP服务器时发生I/O错误: " + e.getMessage() +
", 服务器地址: " + ip + ":" + port + ", 用户名: " + userName);
} catch (Exception e) {
return DocuLib.newDoc("message", "上传过程中发生未预期错误: " + e.getMessage() +
", 服务器地址: " + ip + ":" + port);
} finally {
// 确保在所有情况下都清理临时文件
if (processedFile != null && !processedFile.equals(localFile)) {
try {
if (processedFile.exists()) {
processedFile.delete();
}
} catch (Exception e) {
System.err.println("清理临时文件失败: " + e.getMessage());
}
}
// 关闭FTP连接
try {
if (ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException e) {
System.err.println("关闭FTP连接时发生错误: " + e.getMessage());
}
}
}
/**
* 在文件末尾追加尾标内容
*
* @param originalFile 原始文件
* @param trailerLabel 尾标内容
* @param format 编码格式
* @return 添加尾标后的新文件
* @throws IOException IO异常
*/
/**
* 在文件末尾追加尾标内容
*
* @param originalFile 原始文件
* @param trailerLabel 尾标内容
* @param format
* @return 添加尾标后的新文件
* @throws IOException IO异常
*/
private static File appendTrailerToFile(File originalFile, String trailerLabel, String format) throws IOException {
// 创建临时文件
String tempFileName = originalFile.getAbsolutePath() + ".tmp";
File tempFile = new File(tempFileName);
try (FileInputStream fis = new FileInputStream(originalFile);
InputStreamReader isr = new InputStreamReader(fis, Charset.forName(format));
FileOutputStream fos = new FileOutputStream(tempFile);
OutputStreamWriter osw = new OutputStreamWriter(fos, Charset.forName(format))) {
// 复制原始文件内容
char[] buffer = new char[2048];
int charsRead;
while ((charsRead = isr.read(buffer)) != -1) {
osw.write(buffer, 0, charsRead);
}
// 添加尾标内容
if (trailerLabel != null && !trailerLabel.isEmpty()) {
osw.write(System.lineSeparator());
osw.write(trailerLabel);
}
osw.flush();
}
return tempFile;
}
/**
* 获取当前工作目录(带错误处理)
*
* @param ftpClient FTP客户端
* @return 当前工作目录
*/
private static String getCurrentDirectory(FTPClient ftpClient) {
try {
return ftpClient.printWorkingDirectory();
} catch (IOException e) {
return "无法获取当前目录";
}
}
/**
* 创建远程目录结构
*
* @param ftpClient FTP客户端
* @param remoteDir 远程目录路径
* @return 是否成功创建目录
* @throws IOException IO异常
*/
private static boolean createRemoteDirectory(FTPClient ftpClient, String remoteDir) throws IOException {
// 标准化路径分隔符
remoteDir = remoteDir.replace("\\", "/");
// 移除开头的斜杠(如果存在)
if (remoteDir.startsWith("/")) {
remoteDir = remoteDir.substring(1);
}
// 如果路径为空,直接返回成功
if (remoteDir.isEmpty()) {
return true;
}
String[] dirs = remoteDir.split("/");
String currentDir = "";
for (String dir : dirs) {
if (dir.isEmpty()) continue;
if (currentDir.isEmpty()) {
currentDir = dir;
} else {
currentDir += "/" + dir;
}
// 检查目录是否存在
if (ftpClient.changeWorkingDirectory("/" + currentDir)) {
// 目录存在,继续下一个
continue;
}
// 目录不存在,尝试创建
if (ftpClient.makeDirectory(currentDir)) {
// 创建成功
ftpClient.changeWorkingDirectory("/" + currentDir);
} else {
// 检查是否是因为目录已存在导致创建失败
int replyCode = ftpClient.getReplyCode();
// 550可能表示目录已存在或权限不足
if (replyCode == 550) {
// 尝试切换到目录,确认是否真的存在
if (!ftpClient.changeWorkingDirectory("/" + currentDir)) {
System.err.println("无法访问目录: " + currentDir + ", 错误: " + ftpClient.getReplyString());
return false;
}
} else {
System.err.println("创建目录失败: " + currentDir + ", 错误码: " + replyCode + ", 错误信息: " + ftpClient.getReplyString());
return false;
}
}
}
// 最后切换回根目录
ftpClient.changeWorkingDirectory("/");
return true;
}
/**
* ftp根据文件目录获取第一个包含文件名的文件下载到本地
*
* @param userName 用户名
* @param password 密码
* @param ip ip地址
* @param port 端口
* @param localFilePath 本地保存路径
* @param fileName 文件名
* @param directoryPath 文件目录
* @param keepAliveTimeout 控制连接的KeepAlive超时时间
* @param dataTimeout 数据传输的超时时间
*/
public static Document vagueDownloadFile(String userName, String password, String ip, int port, String localFilePath, String fileName, String directoryPath, int keepAliveTimeout, int dataTimeout) {
FTPClient ftpClient = new FTPClient();
try {
// 连接到 FTP 服务器
ftpClient.connect(ip, port);
ftpClient.setControlEncoding("UTF-8"); // 设置控制连接编码
ftpClient.setAutodetectUTF8(true); // 自动检测UTF-8编码
ftpClient.login(userName, password);
ftpClient.enterLocalPassiveMode();//被动模式
//设置文件传输模式为二进制模式
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
//设置控制连接的KeepAlive超时时间单位(秒),作用:长时间文件传输过程中保持控制连接活跃,防止被服务器断开
ftpClient.setControlKeepAliveTimeout(keepAliveTimeout);
//设置数据传输的超时时间(毫秒)
ftpClient.setDataTimeout(dataTimeout);
directoryPath = new String(directoryPath.getBytes("UTF-8"), "ISO-8859-1");
// 如果 directoryPath 不为空,则切换到指定目录
if (directoryPath != null && !directoryPath.trim().isEmpty()) {
if (!ftpClient.changeWorkingDirectory(directoryPath)) {
return DocuLib.newDoc("message", "找不到目录: " + directoryPath);
}
}
// 确保本地路径以斜杠结尾
if (!localFilePath.endsWith("/") && !localFilePath.endsWith("\\")) {
localFilePath += File.separator;
}
// 获取目录下的文件列表
FTPFile[] files = ftpClient.listFiles();
if (files != null && files.length > 0) {
for (FTPFile file : files) {
if (file.isFile() && file.getName().contains(fileName)) {
String remoteFileName = file.getName();
String localFileName = localFilePath + generateHexId() + "-" + remoteFileName;
File localFile = new File(localFileName);
// 处理中文文件名编码
String encodedFileName = new String(remoteFileName.getBytes("UTF-8"), "ISO-8859-1");
// 下载文件到本地
try (FileOutputStream fos = new FileOutputStream(localFile)) {
InputStream inputStream = ftpClient.retrieveFileStream(encodedFileName);
if (inputStream == null) {
// 检查FTP响应代码以获取更多信息
int replyCode = ftpClient.getReplyCode();
String replyString = ftpClient.getReplyString();
return DocuLib.newDoc("message", "无法获取文件流,FTP响应码: " + replyCode + ", 信息: " + replyString);
}
ReadableByteChannel rbc = Channels.newChannel(inputStream);
ByteBuffer buffer = ByteBuffer.allocate(2048);
while (rbc.read(buffer) != -1) {
buffer.flip();
fos.write(buffer.array(), 0, buffer.limit());
buffer.clear();
}
// 完成文件传输
boolean complete = ftpClient.completePendingCommand();
if (complete) {
Document dto = DocuLib.newDoc("filePath", localFileName);
// 获取文件的最后修改时间
ZonedDateTime zonedDateTime = file.getTimestamp().toInstant().atZone(ZoneId.systemDefault());
LocalDateTime lastModifiedTime = zonedDateTime.toLocalDateTime();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = lastModifiedTime.format(formatter);
dto.put("updateTime", formattedDateTime);
return dto;
} else {
return DocuLib.newDoc("message", "下载文件失败: " + remoteFileName);
}
} catch (IOException e) {
return DocuLib.newDoc("message", "下载文件时发生错误: " + e.getMessage());
}
}
}
}
return DocuLib.newDoc("message", "在目录中找不到包含文件名 " + fileName + " 的文件: " + directoryPath);
} catch (IOException e) {
e.printStackTrace();
return DocuLib.newDoc("message", e.getMessage());
} finally {
try {
if (ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* ftp根据文件目录获取第一个文件下载到本地
*
* @param userName 用户名
* @param password 密码
* @param ip ip地址
* @param port
* @param localFilePath 本地保存路径
* @param directoryPath 文件目录
* @param keepAliveTimeout 控制连接的KeepAlive超时时间
* @param dataTimeout 数据传输的超时时间
*/
public static Document listDownloadGetFirstFile(String userName, String password, String ip, int port, String localFilePath, String directoryPath, int keepAliveTimeout, int dataTimeout) {
FTPClient ftpClient = new FTPClient();
try {
// 连接到 FTP 服务器
ftpClient.connect(ip, port);
ftpClient.setControlEncoding("UTF-8"); // 设置控制连接编码
ftpClient.setAutodetectUTF8(true); // 自动检测UTF-8编码
ftpClient.login(userName, password);
ftpClient.enterLocalPassiveMode();//被动模式
//设置文件传输模式为二进制模式
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
//设置控制连接的KeepAlive超时时间单位(秒),作用:长时间文件传输过程中保持控制连接活跃,防止被服务器断开
ftpClient.setControlKeepAliveTimeout(keepAliveTimeout);
//设置数据传输的超时时间(毫秒)
ftpClient.setDataTimeout(dataTimeout);
directoryPath = new String(directoryPath.getBytes("UTF-8"), "ISO-8859-1");
// 如果 directoryPath 不为空,则切换到指定目录
if (directoryPath != null && !directoryPath.trim().isEmpty()) {
if (!ftpClient.changeWorkingDirectory(directoryPath)) {
return DocuLib.newDoc("message", "找不到目录: " + directoryPath);
}
}
// 确保本地路径以斜杠结尾
if (!localFilePath.endsWith("/") && !localFilePath.endsWith("\\")) {
localFilePath += File.separator;
}
// 获取目录下的文件列表
FTPFile[] files = ftpClient.listFiles();
if (files != null && files.length > 0) {
for (FTPFile file : files) {
if (file.isFile()) {
String remoteFileName = file.getName();
String localFileName = localFilePath + generateHexId() + "-" + remoteFileName;
File localFile = new File(localFileName);
// 处理中文文件名编码
String encodedFileName = new String(remoteFileName.getBytes("UTF-8"), "ISO-8859-1");
// 下载文件到本地
try (FileOutputStream fos = new FileOutputStream(localFile)) {
InputStream inputStream = ftpClient.retrieveFileStream(encodedFileName);
if (inputStream == null) {
// 检查FTP响应代码以获取更多信息
int replyCode = ftpClient.getReplyCode();
String replyString = ftpClient.getReplyString();
return DocuLib.newDoc("message", "无法获取文件流,FTP响应码: " + replyCode + ", 信息: " + replyString);
}
ReadableByteChannel rbc = Channels.newChannel(inputStream);
ByteBuffer buffer = ByteBuffer.allocate(2048);
while (rbc.read(buffer) != -1) {
buffer.flip();
fos.write(buffer.array(), 0, buffer.limit());
buffer.clear();
}
// 完成文件传输
boolean complete = ftpClient.completePendingCommand();
if (complete) {
Document dto = DocuLib.newDoc("filePath", localFileName);
// 获取文件的最后修改时间
ZonedDateTime zonedDateTime = file.getTimestamp().toInstant().atZone(ZoneId.systemDefault());
LocalDateTime lastModifiedTime = zonedDateTime.toLocalDateTime();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = lastModifiedTime.format(formatter);
dto.put("updateTime", formattedDateTime);
return dto;
} else {
return DocuLib.newDoc("message", "下载文件失败: " + remoteFileName);
}
} catch (IOException e) {
return DocuLib.newDoc("message", "下载文件时发生错误: " + e.getMessage());
}
}
}
}
return DocuLib.newDoc("message", "在目录中找不到文件: " + directoryPath);
} catch (IOException e) {
e.printStackTrace();
return DocuLib.newDoc("message", e.getMessage());
} finally {
try {
if (ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* ftp根据文件目录获取全部文件下载到本地
*
* @param username 用户名
* @param password 密码
* @param ipRow ip地址
* @param port 端口
* @param localFilePath 本地保存路径
* @param directoryPath 文件目录
* @param keepAliveTimeout 控制连接的KeepAlive超时时间
* @param dataTimeout 数据传输的超时时间
* @return 下载结果,包含所有下载文件的路径列表
*/
public static Document downloadAllFile(String username, String password, String ipRow, int port,
String localFilePath, String directoryPath,
int keepAliveTimeout, int dataTimeout) {
FTPClient ftpClient = new FTPClient();
try {
// 连接到 FTP 服务器
ftpClient.connect(ipRow, port);
ftpClient.setControlEncoding("UTF-8"); // 设置控制连接编码
ftpClient.setAutodetectUTF8(true); // 自动检测UTF-8编码
ftpClient.login(username, password);
ftpClient.enterLocalPassiveMode(); // 被动模式
// 设置文件传输模式为二进制模式
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
// 设置控制连接的KeepAlive超时时间单位(秒),作用:长时间文件传输过程中保持控制连接活跃,防止被服务器断开
ftpClient.setControlKeepAliveTimeout(keepAliveTimeout);
// 设置数据传输的超时时间(毫秒)
ftpClient.setDataTimeout(dataTimeout);
directoryPath = new String(directoryPath.getBytes("UTF-8"), "ISO-8859-1");
// 如果 directoryPath 不为空,则切换到指定目录
if (directoryPath != null && !directoryPath.trim().isEmpty()) {
if (!ftpClient.changeWorkingDirectory(directoryPath)) {
return DocuLib.newDoc("message", "找不到目录: " + directoryPath);
}
}
// 确保本地路径以斜杠结尾
if (!localFilePath.endsWith("/") && !localFilePath.endsWith("\\")) {
localFilePath += File.separator;
}
// 创建本地目录(如果不存在)
File localDir = new File(localFilePath);
if (!localDir.exists()) {
if (!localDir.mkdirs()) {
return DocuLib.newDoc("message", "无法创建本地目录: " + localFilePath);
}
}
// 获取目录下的文件列表
FTPFile[] files = ftpClient.listFiles();
if (files != null && files.length > 0) {
List<String> downloadedFiles = new ArrayList<>();
String latestDate = "";
// 下载所有文件
for (FTPFile file : files) {
if (file.isFile()) {
String remoteFileName = file.getName();
String localFileName = localFilePath + generateHexId() + "-" + remoteFileName;
File localFile = new File(localFileName);
// 处理中文文件名编码
String encodedFileName = new String(remoteFileName.getBytes("UTF-8"), "ISO-8859-1");
// 下载文件到本地
try (FileOutputStream fos = new FileOutputStream(localFile)) {
InputStream inputStream = ftpClient.retrieveFileStream(encodedFileName);
if (inputStream == null) {
// 检查FTP响应代码以获取更多信息
int replyCode = ftpClient.getReplyCode();
String replyString = ftpClient.getReplyString();
return DocuLib.newDoc("message", "无法获取文件流,FTP响应码: " + replyCode + ", 信息: " + replyString);
}
ReadableByteChannel rbc = Channels.newChannel(inputStream);
ByteBuffer buffer = ByteBuffer.allocate(2048);
while (rbc.read(buffer) != -1) {
buffer.flip();
fos.write(buffer.array(), 0, buffer.limit());
buffer.clear();
}
// 完成文件传输
boolean complete = ftpClient.completePendingCommand();
if (complete) {
downloadedFiles.add(localFileName);
// 获取文件的最后修改时间
ZonedDateTime zonedDateTime = file.getTimestamp().toInstant().atZone(ZoneId.systemDefault());
LocalDateTime lastModifiedTime = zonedDateTime.toLocalDateTime();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = lastModifiedTime.format(formatter);
// 更新最新的文件时间
if (latestDate.isEmpty() || formattedDateTime.compareTo(latestDate) > 0) {
latestDate = formattedDateTime;
}
} else {
return DocuLib.newDoc("message", "下载文件失败: " + remoteFileName);
}
} catch (IOException e) {
return DocuLib.newDoc("message", "下载文件时发生错误: " + remoteFileName + " " + e.getMessage());
}
}
}
Document result = DocuLib.newDoc("filePath", downloadedFiles);
result.put("updateTime", latestDate);
return result;
}
return DocuLib.newDoc("message", "在目录中找不到文件: " + directoryPath);
} catch (IOException e) {
e.printStackTrace();
return DocuLib.newDoc("message", e.getMessage());
} finally {
try {
if (ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* ftp根据文件目录获取最新的一个文件下载到本地
*
* @param userName 用户名
* @param password 密码
* @param ip ip地址
* @param port 端口
* @param localFilePath 本地保存路径
* @param directoryPath 文件目录
* @param keepAliveTimeout 控制连接的KeepAlive超时时间
* @param dataTimeout 数据传输的超时时间
* @return 下载结果
*/
public static Document listDownloadGetLatestFile(String userName, String password, String ip, int port, String localFilePath, String directoryPath, int keepAliveTimeout, int dataTimeout) {
FTPClient ftpClient = new FTPClient();
try {
// 连接到 FTP 服务器
ftpClient.connect(ip, port);
ftpClient.setControlEncoding("UTF-8"); // 设置控制连接编码
ftpClient.setAutodetectUTF8(true); // 自动检测UTF-8编码
ftpClient.login(userName, password);
ftpClient.enterLocalPassiveMode();//被动模式
//设置文件传输模式为二进制模式
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
//设置控制连接的KeepAlive超时时间单位(秒),作用:长时间文件传输过程中保持控制连接活跃,防止被服务器断开
ftpClient.setControlKeepAliveTimeout(keepAliveTimeout);
//设置数据传输的超时时间(毫秒)
ftpClient.setDataTimeout(dataTimeout);
directoryPath = new String(directoryPath.getBytes("UTF-8"), "ISO-8859-1");
// 如果 directoryPath 不为空,则切换到指定目录
if (directoryPath != null && !directoryPath.trim().isEmpty()) {
if (!ftpClient.changeWorkingDirectory(directoryPath)) {
return DocuLib.newDoc("message", "找不到目录: " + directoryPath);
}
}
// 确保本地路径以斜杠结尾
if (!localFilePath.endsWith("/") && !localFilePath.endsWith("\\")) {
localFilePath += File.separator;
}
// 获取目录下的文件列表
FTPFile[] files = ftpClient.listFiles();
if (files != null && files.length > 0) {
// 查找最新的文件
FTPFile latestFile = null;
for (FTPFile file : files) {
if (file.isFile()) {
if (latestFile == null || file.getTimestamp().getTimeInMillis() > latestFile.getTimestamp().getTimeInMillis()) {
latestFile = file;
}
}
}
if (latestFile != null) {
String remoteFileName = latestFile.getName();
String localFileName = localFilePath + generateHexId() + "-" + remoteFileName;
File localFile = new File(localFileName);
// 处理中文文件名编码
String encodedFileName = new String(remoteFileName.getBytes("UTF-8"), "ISO-8859-1");
// 下载文件到本地
try (FileOutputStream fos = new FileOutputStream(localFile)) {
InputStream inputStream = ftpClient.retrieveFileStream(encodedFileName);
if (inputStream == null) {
// 检查FTP响应代码以获取更多信息
int replyCode = ftpClient.getReplyCode();
String replyString = ftpClient.getReplyString();
return DocuLib.newDoc("message", "无法获取文件流,FTP响应码: " + replyCode + ", 信息: " + replyString);
}
ReadableByteChannel rbc = Channels.newChannel(inputStream);
ByteBuffer buffer = ByteBuffer.allocate(2048);
while (rbc.read(buffer) != -1) {
buffer.flip();
fos.write(buffer.array(), 0, buffer.limit());
buffer.clear();
}
// 完成文件传输
boolean complete = ftpClient.completePendingCommand();
if (complete) {
Document dto = DocuLib.newDoc("filePath", localFileName);
// 获取文件的最后修改时间
ZonedDateTime zonedDateTime = latestFile.getTimestamp().toInstant().atZone(ZoneId.systemDefault());
LocalDateTime lastModifiedTime = zonedDateTime.toLocalDateTime();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = lastModifiedTime.format(formatter);
dto.put("updateTime", formattedDateTime);
return dto;
} else {
return DocuLib.newDoc("message", "下载文件失败: " + remoteFileName);
}
} catch (IOException e) {
return DocuLib.newDoc("message", "下载文件时发生错误: " + e.getMessage());
}
}
}
return DocuLib.newDoc("message", "在目录中找不到文件: " + directoryPath);
} catch (IOException e) {
e.printStackTrace();
return DocuLib.newDoc("message", e.getMessage());
} finally {
try {
if (ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* ftp根据文件目录获取最新日期的所有文件下载到本地
*
* @param userName 用户名
* @param password 密码
* @param ip ip地址
* @param port 端口
* @param localFilePath 本地保存路径
* @param directoryPath 文件目录
* @param keepAliveTimeout 控制连接的KeepAlive超时时间
* @param dataTimeout 数据传输的超时时间
* @param downloadedList 已经下载过的文件名列表
* @return 下载结果,包含所有下载文件的路径列表
*/
public static Document listDownloadGetAllLatestDateFiles(String userName, String password, String ip, int port,
String localFilePath, String directoryPath,
int keepAliveTimeout, int dataTimeout, List<String> downloadedList) {
FTPClient ftpClient = new FTPClient();
try {
// 连接到 FTP 服务器
ftpClient.connect(ip, port);
ftpClient.setControlEncoding("UTF-8"); // 设置控制连接编码
ftpClient.setAutodetectUTF8(true); // 自动检测UTF-8编码
ftpClient.login(userName, password);
ftpClient.enterLocalPassiveMode();//被动模式
//设置文件传输模式为二进制模式
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
//设置控制连接的KeepAlive超时时间单位(秒),作用:长时间文件传输过程中保持控制连接活跃,防止被服务器断开
ftpClient.setControlKeepAliveTimeout(keepAliveTimeout);
//设置数据传输的超时时间(毫秒)
ftpClient.setDataTimeout(dataTimeout);
directoryPath = new String(directoryPath.getBytes("UTF-8"), "ISO-8859-1");
// 如果 directoryPath 不为空,则切换到指定目录
if (directoryPath != null && !directoryPath.trim().isEmpty()) {
if (!ftpClient.changeWorkingDirectory(directoryPath)) {
return DocuLib.newDoc("message", "找不到目录: " + directoryPath);
}
}
// 确保本地路径以斜杠结尾
if (!localFilePath.endsWith("/") && !localFilePath.endsWith("\\")) {
localFilePath += File.separator;
}
// 获取目录下的文件列表
FTPFile[] files = ftpClient.listFiles();
if (files != null && files.length > 0) {
// 查找最新时间(精确到分钟)
LocalDateTime latestDateTime = null;
for (FTPFile file : files) {
if (file.isFile()) {
ZonedDateTime zonedDateTime = file.getTimestamp().toInstant().atZone(ZoneId.systemDefault());
LocalDateTime fileDateTime = zonedDateTime.toLocalDateTime().withSecond(0).withNano(0); // 精确到分钟
if (latestDateTime == null || fileDateTime.isAfter(latestDateTime)) {
latestDateTime = fileDateTime;
}
}
}
// 收集所有最新时间的文件
List<FTPFile> latestDateFiles = new ArrayList<>();
if (latestDateTime != null) {
for (FTPFile file : files) {
if (file.isFile()) {
ZonedDateTime zonedDateTime = file.getTimestamp().toInstant().atZone(ZoneId.systemDefault());
LocalDateTime fileDateTime = zonedDateTime.toLocalDateTime().withSecond(0).withNano(0); // 精确到分钟
if (fileDateTime.isEqual(latestDateTime)) {
latestDateFiles.add(file);
}
}
}
}
if (!latestDateFiles.isEmpty()) {
List<String> downloadedFiles = new ArrayList<>();
// 下载所有最新时间的文件
for (FTPFile file : latestDateFiles) {
String remoteFileName = file.getName();
// 过滤掉已经下载过的文件
if (CollUtil.isNotEmpty(downloadedList) && downloadedList.contains(remoteFileName)) {
continue;
}
String localFileName = localFilePath + generateHexId() + "-" + remoteFileName;
File localFile = new File(localFileName);
// 处理中文文件名编码
String encodedFileName = new String(remoteFileName.getBytes("UTF-8"), "ISO-8859-1");
// 下载文件到本地
try (FileOutputStream fos = new FileOutputStream(localFile)) {
InputStream inputStream = ftpClient.retrieveFileStream(encodedFileName);
if (inputStream == null) {
// 检查FTP响应代码以获取更多信息
int replyCode = ftpClient.getReplyCode();
String replyString = ftpClient.getReplyString();
return DocuLib.newDoc("message", "无法获取文件流,FTP响应码: " + replyCode + ", 信息: " + replyString);
}
ReadableByteChannel rbc = Channels.newChannel(inputStream);
ByteBuffer buffer = ByteBuffer.allocate(2048);
while (rbc.read(buffer) != -1) {
buffer.flip();
fos.write(buffer.array(), 0, buffer.limit());
buffer.clear();
}
// 完成文件传输
boolean complete = ftpClient.completePendingCommand();
if (complete) {
downloadedFiles.add(localFileName);
} else {
return DocuLib.newDoc("message", "下载文件失败: " + remoteFileName);
}
} catch (IOException e) {
return DocuLib.newDoc("message", "下载文件时发生错误: " + remoteFileName + " " + e.getMessage());
}
}
Document result = DocuLib.newDoc("filePath", downloadedFiles);
// 添加最新时间信息
if (!latestDateFiles.isEmpty()) {
FTPFile firstFile = latestDateFiles.get(0);
ZonedDateTime zonedDateTime = firstFile.getTimestamp().toInstant().atZone(ZoneId.systemDefault());
LocalDateTime lastModifiedTime = zonedDateTime.toLocalDateTime();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = lastModifiedTime.format(formatter);
result.put("updateTime", formattedDateTime);
}
return result;
}
}
return DocuLib.newDoc("message", "在目录中找不到文件: " + directoryPath);
} catch (IOException e) {
e.printStackTrace();
return DocuLib.newDoc("message", e.getMessage());
} finally {
try {
if (ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 从本地上传文件到FTP服务器
*
* @param userName 用户名
* @param password 密码
* @param ip ip地址
* @param localFilePath 本地保存文件完整路径
* @param fileName 文件名
* @return
*/
public static Document uploadFile(String userName, String password, String ip, String localFilePath, String fileName) {
String ftpUrl = StrUtil.format("ftp://{}:{}@{}/{}", userName, password, ip, fileName);
File file = new File(localFilePath);
try {
// 检查文件是否存在
if (!file.exists()) {
return DocuLib.newDoc("message", "找不到文件: " + localFilePath).append("check", false);
}
URL url = new URL(ftpUrl);
URLConnection urlConnection = url.openConnection();
urlConnection.setDoOutput(true);
try (InputStream in = new FileInputStream(file);
OutputStream out = urlConnection.getOutputStream()) {
byte[] buffer = new byte[2048];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
out.flush();
return DocuLib.newDoc("check", true);
} catch (Exception e) {
return DocuLib.newDoc("message", "上传文件时发生错误: " + e.getMessage()).append("check", false);
}
} catch (MalformedURLException e) {
return DocuLib.newDoc("message", "无效的URL格式: " + e.getMessage()).append("check", false);
} catch (FileNotFoundException e) {
return DocuLib.newDoc("message", "本地文件未找到: " + e.getMessage()).append("check", false);
} catch (IOException e) {
return DocuLib.newDoc("message", "I/O错误: " + e.getMessage()).append("check", false);
} catch (Exception e) {
return DocuLib.newDoc("message", "其他异常: " + e.getMessage()).append("check", false);
}
}
/**
* 生成一个十六位数的ID
*
* @return 十六位数的ID
*/
private static String generateHexId() {
UUID uuid = UUID.randomUUID();
String uuidStr = uuid.toString().replace("-", ""); // 去掉UUID中的连字符
return uuidStr.substring(0, 16); // 截取前16位
}
}