CuteFTPUtils
对FTPClient的二次封装;
注意:FTPClient 有主目录的。
打个比方, FTPClient1 处于 a/b/c 的c目录下,则FTPClient1不能对a 目录下的文件操作。得切换主目录到a目录下,
或者新建另一个FTPClient2 对象。
|
方法摘要 | |
|
static CuteFTPUtils |
getInstance() 创建并返回此对象,并登录 |
|
boolean |
checkLoginState() 检测FtpClient登录状态 |
|
boolean |
login() 登录FtpClient |
| Function<FtpFileInfo, Boolean> | onUploadFileAfter() 上传后触发 |
| boolean | uploadFile(String localFileName, String ftpDirName, String ftpFileName) 文件上传 |
| boolean | uploadFile(String localFileName, String ftpDirName, String ftpFileName, boolean deleteLocalFile) 文件上传;是否删除本地文件 |
| boolean | uploadFile(FileInputStream uploadInputStream, String ftpDirName, String ftpFileName) 文件上传;传入文件流 |
| InputStream | getInputStream (String ftpDirName, String ftpFileName) 得到ftp库内指定文件的文件流(用于下载) |
| boolean | downloadFile(String ftpDirName, String ftpFileName, String localFileFullName) 下载文件到指定的本地文件库 |
| boolean | existFile(String ftpDirName,String ftpFileName) 判断指定路径下是否存在该文件 |
| FTPClient | getFTPClient () 返回一个FTPClient 对象(与登录时实例化的FTPClient是同一个对象) |
| FTPFile[] | getFTPFile(String ftpDirName) 获得指定目录下的所有文件 |
| boolean | removeFile(String ftpFileName) 删除单文件;完整路径+文件名+文件后缀名 |
| boolean | removeFileByName(String ftpDirName , String ftpFileName) 删除文件名相同的多文件,无视后缀 |
| boolean | removeFileAndDirByName(String path , String ftpFileName) 删除文件名相同的 文件+文件夹 |
| boolean | removeDir(String dir) 删除空目录 |
| boolean | removeDirectoryALLFile(String pathName,boolean directory) 清空文件夹 / 删除文件夹 |
| boolean | createDir(String dir) 创建目录 |
| private void | closeFtpConnection() 销毁ftp连接 |
| void | close() 销毁ftp连接,释放对象保存的资源(如打开的文件) |
| static | combine(String... args) 合并路径 |
源码

1 import java.io.Closeable;
2 import java.io.File;
3 import java.io.FileInputStream;
4 import java.io.FileOutputStream;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.util.function.Function;
8
9 import org.apache.commons.lang3.StringUtils;
10 import org.apache.commons.net.ftp.FTPClient;
11 import org.apache.commons.net.ftp.FTPClientConfig;
12 import org.apache.commons.net.ftp.FTPFile;
13 import org.apache.commons.net.ftp.FTPReply;
14 import org.slf4j.Logger;
15 import org.slf4j.LoggerFactory;
16
17 /**
18 * ftp 上传下载公共类
19 *
20 * @author QGuo
21 *
22 */
23 public class CuteFTPUtils implements Closeable {
24 private final Logger logger = LoggerFactory.getLogger(this.getClass());
25
26 private FTPClient ftp = null;
27 boolean _isLogin = false;
28
29 public static CuteFTPUtils getInstance() {
30 CuteFTPUtils cuteFTPUtils = new CuteFTPUtils();
31 cuteFTPUtils.login();
32 return cuteFTPUtils;
33 }
34
35 //判断当前ftp链接状态
36 public boolean checkLoginState() {
37 int reply = ftp.getReplyCode();
38 if (!FTPReply.isPositiveCompletion(reply)) {
39 System.err.println("FTP服务器拒绝连接 ");
40 return false;
41 } else {
42 return true;
43 }
44
45 }
46
47 /**
48 *
49 * 登录
50 */
51 public boolean login() {
52 ftp = new FTPClient();
53 String hostname = PropertyUtil.getProperty("FTP_HOSTNAME");
54 int port = Integer.valueOf(PropertyUtil.getProperty("FTP_PORT"));
55 String username = PropertyUtil.getProperty("FTP_USERNAME");
56 String password = PropertyUtil.getProperty("FTP_PASSWORD");
57 try {
58 // 连接
59 ftp.connect(hostname, port);
60 _isLogin = ftp.login(username, password);
61 logger.info(_isLogin ? "登录成功" : "登录失败");
62 // 检测连接是否成功
63 int reply = ftp.getReplyCode();
64 if (!FTPReply.isPositiveCompletion(reply)) {
65 System.err.println("FTP服务器拒绝连接 ");
66 return false;
67 }
68 return true;
69 } catch (Exception ex) {
70 ex.printStackTrace();
71 return false;
72 }
73 }
74
75 /**
76 * 上传后触发
77 */
78 public Function<FtpFileInfo, Boolean> onUploadFileAfter;
79
80 /**
81 *
82 * ftp上传文件
83 *
84 * @param localFileName
85 * 待上传文件
86 * @param ftpDirName
87 * ftp 目录名
88 * @param ftpFileName
89 * ftp目标文件
90 * @return true||false
91 */
92 public boolean uploadFile(String localFileName, String ftpDirName, String ftpFileName) {
93 return uploadFile(localFileName, ftpDirName, ftpFileName, false);
94 }
95
96 /**
97 *
98 * ftp上传文件
99 *
100 * @param localFileName
101 * 待上传文件
102 * @param ftpDirName
103 * ftp 目录名
104 * @param ftpFileName
105 * ftp目标文件
106 * @param deleteLocalFile
107 * 是否删除本地文件
108 * @return true||false
109 */
110 public boolean uploadFile(String localFileName, String ftpDirName, String ftpFileName, boolean deleteLocalFile) {
111
112 printFormat("准备上传 [{0}] 到 ftp://{1}/{2}", localFileName, ftpDirName, ftpFileName);
113 if (StringUtils.isEmpty(ftpFileName))
114 throw new RuntimeException("上传文件必须填写文件名!");
115
116 File srcFile = new File(localFileName);
117 if (!srcFile.exists())
118 throw new RuntimeException("文件不存在:" + localFileName);
119
120 try (FileInputStream fis = new FileInputStream(srcFile)) {
121 // 上传文件
122 boolean flag = uploadFile(fis, ftpDirName, ftpFileName);
123 // 上传前事件
124 if (onUploadFileAfter != null) {
125 onUploadFileAfter.apply(new FtpFileInfo(localFileName, ftpDirName, ftpFileName));
126 }
127 // 删除文件
128 if (deleteLocalFile) {
129 srcFile.delete();
130 printFormat("ftp删除源文件:{0}", srcFile);
131 }
132 fis.close();
133 return flag;
134 } catch (Exception e) {
135 e.printStackTrace();
136 return false;
137 } finally {
138 }
139 }
140
141 /**
142 *
143 * ftp上传文件 (使用inputstream)
144 *
145 * @param localFileName
146 * 待上传文件
147 * @param ftpDirName
148 * ftp 目录名
149 * @param ftpFileName
150 * ftp目标文件
151 * @return true||false
152 */
153 public boolean uploadFile(FileInputStream uploadInputStream, String ftpDirName, String ftpFileName) {
154 printFormat("准备上传 [流] 到 ftp://{0}/{1}", ftpDirName, ftpFileName);
155 // if(StringExtend.isNullOrEmpty(ftpDirName))
156 // ftpDirName="/";
157 if (StringUtils.isEmpty(ftpFileName))
158 throw new RuntimeException("上传文件必须填写文件名!");
159
160 try {
161 // 设置上传目录(没有则创建)
162 if (!createDir(ftpDirName)) {
163 throw new RuntimeException("切入FTP目录失败:" + ftpDirName);
164 }
165 ftp.setBufferSize(1024);
166 // 解决上传中文 txt 文件乱码
167 ftp.setControlEncoding("GBK");
168 FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);
169 conf.setServerLanguageCode("zh");
170
171 // 设置文件类型(二进制)
172 ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
173 // 上传
174 String fileName = new String(ftpFileName.getBytes("GBK"), "iso-8859-1");
175 if (this.ftp.storeFile(fileName, uploadInputStream)) {
176 uploadInputStream.close();
177 printFormat("文件上传成功:{0}/{1}", ftpDirName, ftpFileName);
178 return true;
179 }
180
181 return false;
182 } catch (Exception e) {
183 e.printStackTrace();
184 return false;
185 } finally {
186 }
187 }
188
189 /**
190 * 获取ftp上文件,得到该文件流
191 * @param ftpDirName 目录
192 * @param ftpFileName 文件名称(带后缀)
193 * @return
194 */
195 public InputStream getInputStream (String ftpDirName, String ftpFileName) {
196 try {
197 if ("".equals(ftpDirName))
198 ftpDirName = "/";
199 String dir = new String(ftpDirName.getBytes("GBK"), "iso-8859-1");
200 if (!ftp.changeWorkingDirectory(dir)) {
201 System.out.println("切换目录失败:" + ftpDirName);
202 }
203 FTPFile[] fs = ftp.listFiles();
204 String fileName = new String(ftpFileName.getBytes("GBK"), "iso-8859-1");
205 for (FTPFile ff : fs) {
206 if (ff.getName().equals(fileName)) {
207 System.out.println("成功获取ftp文件流:" + ftpFileName + ";目录:" + ftpDirName);
208 return ftp.retrieveFileStream(ftpFileName);
209 }
210 }
211 System.out.println("获取ftp文件流,失败:" + ftpFileName + ";目录:" + ftpDirName);
212 } catch (Exception e) {
213 e.printStackTrace();
214 }
215 return null;
216
217 }
218
219 /**
220 * 下载文件
221 *
222 * @param ftpDirName
223 * ftp目录名
224 * @param ftpFileName
225 * ftp文件名
226 * @param localFileFullName
227 * 本地文件名
228 */
229 public boolean downloadFile(String ftpDirName, String ftpFileName, String localFileFullName) {
230 try {
231 if ("".equals(ftpDirName))
232 ftpDirName = "/";
233 String dir = new String(ftpDirName.getBytes("GBK"), "iso-8859-1");
234 if (!ftp.changeWorkingDirectory(dir)) {
235 System.out.println("切换目录失败:" + ftpDirName);
236 return false;
237 }
238 FTPFile[] fs = ftp.listFiles();
239 String fileName = new String(ftpFileName.getBytes("GBK"), "iso-8859-1");
240 for (FTPFile ff : fs) {
241 if (ff.getName().equals(fileName)) {
242 FileOutputStream is = new FileOutputStream(new File(localFileFullName));
243 ftp.retrieveFile(ff.getName(), is);
244 is.close();
245 System.out.println("下载ftp文件,已下载:" + localFileFullName);
246 return true;
247 }
248 }
249 System.out.println("下载ftp文件,失败:" + ftpFileName + ";目录:" + ftpDirName);
250 return false;
251 } catch (Exception e) {
252 e.printStackTrace();
253 return false;
254 }
255 }
256
257 /**
258 * 判断指定路径下是否存在改文件
259 * @param ftpDirName
260 * @param ftpFileName
261 * @return
262 */
263 public boolean existFile(String ftpDirName,String ftpFileName) {
264 FTPFile[] fileArray = null;
265 FTPFile file = null;
266 try {
267 fileArray = ftp.listFiles(ftpDirName);
268 } catch (IOException e) {
269 // TODO Auto-generated catch block
270 e.printStackTrace();
271 }
272 for (int i = 0; i < fileArray.length; i++) {
273 file = fileArray[i];
274 //确认该file 为 文件
275 if (file.isFile()) {
276 //当字段相等时,确认存在
277 if (ftpFileName.equals(file.getName())) {
278 return true;
279 }
280 }
281 }
282 return false;
283 }
284
285 /**
286 * 返回FTPClient 对象
287 * @return
288 */
289 public FTPClient getFTPClient () {
290 return this.ftp;
291 }
292
293 /**
294 * 获得指定目录下的所有文件
295 * @param ftpDirName
296 * @return
297 */
298 public FTPFile[] getFTPFile(String ftpDirName) {
299 FTPFile[] ftpFile = null ;
300 try {
301 ftpFile = ftp.listFiles(ftpDirName);
302 } catch (IOException e) {
303 // TODO Auto-generated catch block
304 e.printStackTrace();
305 }
306
307 return ftpFile;
308 }
309
310 /**
311 *
312 * 删除ftp上的文件(完整路径,包括文件后缀名)
313 * @param ftpFileName
314 * @return true || false
315 */
316 public boolean removeFile(String ftpFileName) {
317 boolean flag = false;
318 printFormat("待删除文件:{0}", ftpFileName);
319 try {
320 ftpFileName = new String(ftpFileName.getBytes("GBK"), "iso-8859-1");
321 flag = ftp.deleteFile(ftpFileName);
322 printFormat("删除文件:[{0}]", flag ? "成功" : "失败");
323 return flag;
324 } catch (IOException e) {
325 e.printStackTrace();
326 return false;
327 }
328 }
329
330 /**
331 * 删除库中,所有文件名相同的文件(路径+文件名)不用后缀名
332 * @param path 文件路径
333 * @param ftpFileName 不带后缀的文件名
334 * @return
335 */
336 public boolean removeFileByName(String ftpDirName , String ftpFileName) {
337 boolean flag = false;
338 FTPFile[] tempFile;
339 try {
340 tempFile = ftp.listFiles(ftpDirName);
341 for (int i = 0; i < tempFile.length; i++) {
342 String fileName = null ;
343 //只删除文件,文件夹不处理
344 if (tempFile[i].isFile()) {
345 fileName = tempFile[i].getName();
346 } else {
347 continue;
348 }
349 if (ftpFileName.equals(fileName.substring(0, fileName.lastIndexOf(".")))) {
350 System.out.println("将被删除的文件名:" + fileName);
351 try {
352 ftpFileName = new String(ftpFileName.getBytes("GBK"), "iso-8859-1");
353 flag = ftp.deleteFile(ftpDirName+"/"+tempFile[i].getName());
354 System.out.println("文件" + fileName + "删除成功");
355 } catch (IOException e) {
356 // TODO Auto-generated catch block
357 System.out.println("文件" + fileName + "删除失败");
358 e.printStackTrace();
359 };
360 }
361 }
362 } catch (IOException e1) {
363 e1.printStackTrace();
364 System.out.println(e1.getMessage());
365 }
366 return flag;
367 }
368
369 /**
370 * 删除库中,所有文件名相同的文件(路径+文件名)不用后缀名;
371 * 包括同名的文件夹
372 * @param path 文件路径
373 * @param ftpFileName 不带后缀的文件名
374 * @return
375 */
376 public boolean removeFileAndDirByName(String path , String ftpFileName) {
377 boolean flag = false;
378 FTPFile[] tempFile;
379 try {
380 tempFile = ftp.listFiles(path);
381 for (int i = 0; i < tempFile.length; i++) {
382 String fileName = null ;
383 //只删除文件,文件夹不处理
384 if (tempFile[i].isFile()) {
385 fileName = tempFile[i].getName();
386 } else if (tempFile[i].isDirectory()){
387 //删除文件夹
388 removeDirectoryALLFile(path+"/"+tempFile[i].getName(),true);
389 } else {
390 continue;
391 }
392
393 if (ftpFileName.equals(fileName.substring(0, fileName.lastIndexOf(".")))) {
394 System.out.println("将被删除的文件名:" + fileName);
395 try {
396 ftpFileName = new String(ftpFileName.getBytes("GBK"), "iso-8859-1");
397 flag = ftp.deleteFile(path+"/"+tempFile[i].getName());
398 System.out.println("文件" + fileName + "删除成功");
399 } catch (IOException e) {
400 // TODO Auto-generated catch block
401 System.out.println("文件" + fileName + "删除失败");
402 e.printStackTrace();
403 };
404 }
405 }
406 } catch (IOException e1) {
407 e1.printStackTrace();
408 System.out.println(e1.getMessage());
409 }
410 return flag;
411 }
412
413 /**
414 * 删除空目录
415 *
416 * @param dir
417 * @return
418 */
419 public boolean removeDir(String dir) {
420 if (dir.startsWith("/"))
421 dir = "/" + dir;
422 try {
423 String d = new String(dir.toString().getBytes("GBK"), "iso-8859-1");
424 return ftp.removeDirectory(d);
425 } catch (Exception e) {
426 e.printStackTrace();
427 return false;
428 }
429 }
430
431 /**
432 * 删除Ftp上的文件夹(可控制是否保留文件夹) 包括其中的文件
433 * 注:① 删除文件夹,请携带 "/" ② false亦保留子文件夹
434 * @param directory ture 删除文件夹 false保留文件夹
435 * @param pathName 文件夹路径
436 * @return 是否成功
437 */
438 public boolean removeDirectoryALLFile(String pathName,boolean directory){
439 try
440 {
441 FTPFile[] files = ftp.listFiles(pathName);
442 if (null != files && files.length > 0)
443 {
444 for (FTPFile file : files)
445 {
446 if (file.isDirectory())
447 {
448 removeDirectoryALLFile(pathName + "/" + file.getName(),directory);
449 // 切换到父目录,不然删不掉文件夹
450 ftp.changeWorkingDirectory(pathName.substring(0, pathName.lastIndexOf("/")));
451 ftp.removeDirectory(pathName);
452 }
453 else
454 {
455 if (!ftp.deleteFile(pathName + "/" + file.getName()))
456 {
457 System.out.println("删除指定文件" + pathName + "/" + file.getName() + "失败!");
458 return false;
459 }
460 }
461 }
462 }
463 // 切换到父目录,不然删不掉文件夹
464 ftp.changeWorkingDirectory(pathName.substring(0, pathName.lastIndexOf("/")));
465 if (directory)
466 ftp.removeDirectory(pathName);
467 }
468 catch (IOException e)
469 {
470 logger.error("删除指定文件夹" + pathName + "失败:" + e);
471 e.printStackTrace();
472 return false;
473 }
474
475 return true;
476 }
477
478 /**
479 * 创建目录(有则切换目录,没有则创建目录)
480 *
481 * @param dir
482 * @return
483 */
484 public boolean createDir(String dir) {
485 if (StringUtils.isEmpty(dir))
486 return true;
487 String d;
488 try {
489 // 目录编码,解决中文路径问题
490 d = new String(dir.toString().getBytes("GBK"), "iso-8859-1");
491 // 尝试切入目录
492 if (ftp.changeWorkingDirectory(d))
493 return true;
494 dir = trimStart(dir, "/");
495 dir = trimEnd(dir, "/");
496 String[] arr = dir.split("/");
497 StringBuffer sbfDir = new StringBuffer();
498 // 循环生成子目录
499 for (String s : arr) {
500 sbfDir.append("/");
501 sbfDir.append(s);
502 // 目录编码,解决中文路径问题
503 d = new String(sbfDir.toString().getBytes("GBK"), "iso-8859-1");
504 // 尝试切入目录
505 if (ftp.changeWorkingDirectory(d))
506 continue;
507 if (!ftp.makeDirectory(d)) {
508 System.out.println("[失败]ftp创建目录:" + sbfDir.toString());
509 return false;
510 }
511 System.out.println("[成功]创建ftp目录:" + sbfDir.toString());
512 }
513 // 将目录切换至指定路径
514 return ftp.changeWorkingDirectory(d);
515 } catch (Exception e) {
516 e.printStackTrace();
517 return false;
518 }
519 }
520
521 /**
522 *
523 * 销毁ftp连接
524 *
525 */
526 private void closeFtpConnection() {
527 _isLogin = false;
528 if (ftp != null) {
529 if (ftp.isConnected()) {
530 try {
531 ftp.logout();
532 ftp.disconnect();
533 logger.info("ftp:退出");
534 } catch (IOException e) {
535 e.printStackTrace();
536 }
537 }
538 }
539 }
540
541 /**
542 *
543 * 销毁ftp连接
544 *
545 */
546 @Override
547 public void close() {
548 this.closeFtpConnection();
549 }
550
551 public static class FtpFileInfo {
552 public FtpFileInfo(String srcFile, String ftpDirName, String ftpFileName) {
553 this.ftpDirName = ftpDirName;
554 this.ftpFileName = ftpFileName;
555 this.srcFile = srcFile;
556 }
557
558 String srcFile;
559 String ftpDirName;
560 String ftpFileName;
561 String ftpFileFullName;
562
563 public String getSrcFile() {
564 return srcFile;
565 }
566
567 public void setSrcFile(String srcFile) {
568 this.srcFile = srcFile;
569 }
570
571 public String getFtpDirName() {
572 return ftpDirName;
573 }
574
575 public void setFtpDirName(String ftpDirName) {
576 this.ftpDirName = ftpDirName;
577 }
578
579 public String getFtpFileName() {
580 return ftpFileName;
581 }
582
583 public void setFtpFileName(String ftpFileName) {
584 this.ftpFileName = ftpFileName;
585 }
586
587 /**
588 * 获取ftp上传文件的完整路径名
589 * @return
590 */
591 public String getFtpFileFullName() {
592 return combine("/", ftpDirName, ftpFileName);
593 }
594
595 }
596
597 /**
598 * 删除起始字符
599 *
600 * @param s
601 * @return
602 */
603 public static String trimStart(String str, String trim) {
604 if (str == null)
605 return null;
606 return str.replaceAll("^(" + trim + ")+", "");
607 }
608
609 /**
610 * 删除末尾字符
611 *
612 * @param s
613 * @return
614 */
615 public static String trimEnd(String str, String trim) {
616 if (str == null)
617 return null;
618 return str.replaceAll("(" + trim + ")+$", "");
619 }
620
621 /**
622 * 格式化输出,打印信息到控制台
623 *
624 * @param format
625 * @param args
626 */
627 public static void printFormat(String format, Object... args) {
628 if (args == null) {
629 System.out.println(format);
630 }
631 System.out.println(java.text.MessageFormat.format(format, args));
632 }
633
634 /**
635 * 合并路径
636 *
637 * @param args
638 * @return
639 */
640 public static String combine(String... args) {
641 if (args == null || args.length == 0)
642 return "";
643 StringBuffer sbf = new StringBuffer();
644 for (String s : args) {
645 // 首位地址只删除尾部正反斜杠
646 if (sbf.length() == 0) {
647 sbf.append(s.replaceAll("/{1,}$|\\{1,}$", ""));
648 continue;
649 }
650
651 if (sbf.length() > 0)
652 sbf.append("/");
653 // 去除首尾正反斜杠
654 sbf.append(s.replaceAll("^/{1,}|^\\{1,}", "").replaceAll("/{1,}$|\\{1,}$", ""));
655 }
656
657 return sbf.toString();
658 }
659
660 }
本文介绍了一个基于FTPClient的工具类CuteFTPUtils,它提供了文件上传、下载、删除等功能,并解决了中文路径及文件名的问题。通过示例代码展示了如何使用该工具类进行FTP操作。
753

被折叠的 条评论
为什么被折叠?



