1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
| package com.example.util;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import com.example.config.FtpProperties;
import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
@Component
public class FtpUtil {
private static final Logger logger = LoggerFactory.getLogger(FtpUtil.class);
@Autowired
private FtpConnectionFactory connectionFactory;
@Autowired
private FtpProperties ftpProperties;
/**
* 上傳檔案
*
* @param localFile 本地檔案
* @param remotePath 遠端路徑(相對於 basePath)
* @return 上傳是否成功
*/
public boolean uploadFile(File localFile, String remotePath) {
if (!localFile.exists() || !localFile.isFile()) {
logger.error("本地檔案不存在或不是檔案:{}", localFile.getAbsolutePath());
return false;
}
try (FileInputStream fis = new FileInputStream(localFile)) {
return uploadFile(fis, remotePath, localFile.getName());
} catch (IOException e) {
logger.error("讀取本地檔案失敗:{}", e.getMessage());
return false;
}
}
/**
* 上傳檔案流
*
* @param inputStream 輸入流
* @param remotePath 遠端路徑
* @param fileName 檔案名稱
* @return 上傳是否成功
*/
public boolean uploadFile(InputStream inputStream, String remotePath, String fileName) {
FTPClient ftpClient = null;
try {
ftpClient = connectionFactory.getConnection();
// 確保遠端目錄存在
String fullPath = buildFullPath(remotePath);
createDirectoryIfNotExists(ftpClient, fullPath);
// 切換到目標目錄
if (!ftpClient.changeWorkingDirectory(fullPath)) {
logger.error("無法切換到目錄:{}", fullPath);
return false;
}
// 上傳檔案
boolean result = ftpClient.storeFile(fileName, inputStream);
if (result) {
logger.info("檔案上傳成功:{}/{}", fullPath, fileName);
} else {
logger.error("檔案上傳失敗:{}/{}", fullPath, fileName);
}
return result;
} catch (IOException e) {
logger.error("上傳檔案時發生錯誤:{}", e.getMessage());
return false;
} finally {
connectionFactory.returnConnection(ftpClient);
closeQuietly(inputStream);
}
}
/**
* 下載檔案
*
* @param remotePath 遠端路徑
* @param fileName 檔案名稱
* @param localFile 本地檔案
* @return 下載是否成功
*/
public boolean downloadFile(String remotePath, String fileName, File localFile) {
FTPClient ftpClient = null;
try {
ftpClient = connectionFactory.getConnection();
String fullPath = buildFullPath(remotePath);
if (!ftpClient.changeWorkingDirectory(fullPath)) {
logger.error("遠端目錄不存在:{}", fullPath);
return false;
}
// 確保本地目錄存在
File parentDir = localFile.getParentFile();
if (!parentDir.exists()) {
parentDir.mkdirs();
}
try (FileOutputStream fos = new FileOutputStream(localFile)) {
boolean result = ftpClient.retrieveFile(fileName, fos);
if (result) {
logger.info("檔案下載成功:{}/{} -> {}", fullPath, fileName, localFile.getAbsolutePath());
} else {
logger.error("檔案下載失敗:{}/{}", fullPath, fileName);
}
return result;
}
} catch (IOException e) {
logger.error("下載檔案時發生錯誤:{}", e.getMessage());
return false;
} finally {
connectionFactory.returnConnection(ftpClient);
}
}
/**
* 刪除檔案
*
* @param remotePath 遠端路徑
* @param fileName 檔案名稱
* @return 刪除是否成功
*/
public boolean deleteFile(String remotePath, String fileName) {
FTPClient ftpClient = null;
try {
ftpClient = connectionFactory.getConnection();
String fullPath = buildFullPath(remotePath);
if (!ftpClient.changeWorkingDirectory(fullPath)) {
logger.error("遠端目錄不存在:{}", fullPath);
return false;
}
boolean result = ftpClient.deleteFile(fileName);
if (result) {
logger.info("檔案刪除成功:{}/{}", fullPath, fileName);
} else {
logger.error("檔案刪除失敗:{}/{}", fullPath, fileName);
}
return result;
} catch (IOException e) {
logger.error("刪除檔案時發生錯誤:{}", e.getMessage());
return false;
} finally {
connectionFactory.returnConnection(ftpClient);
}
}
/**
* 列出目錄中的檔案
*
* @param remotePath 遠端路徑
* @return 檔案列表
*/
public List<FtpFileInfo> listFiles(String remotePath) {
FTPClient ftpClient = null;
List<FtpFileInfo> fileList = new ArrayList<>();
try {
ftpClient = connectionFactory.getConnection();
String fullPath = buildFullPath(remotePath);
if (!ftpClient.changeWorkingDirectory(fullPath)) {
logger.error("遠端目錄不存在:{}", fullPath);
return fileList;
}
FTPFile[] ftpFiles = ftpClient.listFiles();
for (FTPFile ftpFile : ftpFiles) {
FtpFileInfo fileInfo = new FtpFileInfo();
fileInfo.setName(ftpFile.getName());
fileInfo.setSize(ftpFile.getSize());
fileInfo.setDirectory(ftpFile.isDirectory());
fileInfo.setModifyTime(ftpFile.getTimestamp());
fileList.add(fileInfo);
}
logger.info("成功列出目錄 {} 中的 {} 個檔案", fullPath, fileList.size());
} catch (IOException e) {
logger.error("列出檔案時發生錯誤:{}", e.getMessage());
} finally {
connectionFactory.returnConnection(ftpClient);
}
return fileList;
}
/**
* 檢查檔案是否存在
*
* @param remotePath 遠端路徑
* @param fileName 檔案名稱
* @return 檔案是否存在
*/
public boolean fileExists(String remotePath, String fileName) {
FTPClient ftpClient = null;
try {
ftpClient = connectionFactory.getConnection();
String fullPath = buildFullPath(remotePath);
if (!ftpClient.changeWorkingDirectory(fullPath)) {
return false;
}
FTPFile[] files = ftpClient.listFiles(fileName);
return files != null && files.length > 0;
} catch (IOException e) {
logger.error("檢查檔案存在性時發生錯誤:{}", e.getMessage());
return false;
} finally {
connectionFactory.returnConnection(ftpClient);
}
}
/**
* 建立完整路徑
*/
private String buildFullPath(String remotePath) {
String basePath = ftpProperties.getBasePath();
if (!StringUtils.hasText(remotePath)) {
return basePath;
}
// 規範化路徑
String normalizedBasePath = basePath.endsWith("/") ? basePath : basePath + "/";
String normalizedRemotePath = remotePath.startsWith("/") ? remotePath.substring(1) : remotePath;
return normalizedBasePath + normalizedRemotePath;
}
/**
* 遞迴建立目錄
*/
private void createDirectoryIfNotExists(FTPClient ftpClient, String path) throws IOException {
String[] pathElements = path.split("/");
StringBuilder currentPath = new StringBuilder();
for (String element : pathElements) {
if (StringUtils.hasText(element)) {
currentPath.append("/").append(element);
if (!ftpClient.changeWorkingDirectory(currentPath.toString())) {
if (ftpClient.makeDirectory(currentPath.toString())) {
logger.debug("建立目錄:{}", currentPath.toString());
} else {
throw new IOException("無法建立目錄:" + currentPath.toString());
}
}
}
}
}
/**
* 安靜地關閉資源
*/
private void closeQuietly(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException e) {
// 忽略關閉時的錯誤
}
}
}
}
|
留言討論