FtpUtils.java 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. package io.platform.utils;
  2. import cn.hutool.core.img.ImgUtil;
  3. import cn.hutool.core.io.FileUtil;
  4. import org.apache.commons.lang.StringUtils;
  5. import org.apache.commons.net.ftp.*;
  6. import org.slf4j.Logger;
  7. import org.slf4j.LoggerFactory;
  8. import org.springframework.beans.factory.annotation.Value;
  9. import org.springframework.stereotype.Component;
  10. import java.awt.*;
  11. import java.io.*;
  12. import java.net.SocketException;
  13. import java.util.regex.Pattern;
  14. /**
  15. * Created by chen on 2017/12/27.
  16. */
  17. @Component
  18. public class FtpUtils {
  19. @Value("${ftp.userName}")
  20. private String userName; //登录名
  21. @Value("${ftp.password}")
  22. private String password; //密码
  23. @Value("${ftp.ftpHostName}")
  24. private String ftpHostName; //ftp地址
  25. @Value("${ftp.port}")
  26. private int port; //端口
  27. @Value("${ftp.rootPath}")
  28. private String rootPath; // upload/admin/
  29. @Value("${ftp.httpAddr}")
  30. private String httpAddr; // http://117.50.20.112/upload/
  31. @Value("${ftp.tempDir}")
  32. private String tempDir;
  33. private FTPClient ftpClient = new FTPClient();
  34. private OutputStream os = null;
  35. private InputStream is = null;
  36. private Logger logger = LoggerFactory.getLogger(getClass());
  37. private Pattern pattern = Pattern.compile("\\d{8}"); //8位数字
  38. /**
  39. * 建立链接
  40. */
  41. private void connect() {
  42. try {
  43. logger.info("开始链接..." + ftpHostName +"..."+ port);
  44. ftpClient.connect(ftpHostName, port);
  45. int reply = ftpClient.getReplyCode(); //ftp响应码
  46. logger.error("ftp响应状态码"+reply);
  47. if (!FTPReply.isPositiveCompletion(reply)) { //ftp拒绝链接
  48. logger.error("ftp拒绝链接...");
  49. ftpClient.disconnect();
  50. }
  51. ftpClient.login(userName, password);
  52. ftpClient.enterLocalPassiveMode(); //设置被动模式 通知server端开通端口传输数据
  53. ftpClient.setBufferSize(256);
  54. ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
  55. ftpClient.setControlEncoding("utf-8");
  56. logger.info("登录成功!");
  57. } catch (SocketException e) {
  58. // TODO Auto-generated catch block
  59. logger.error(e.getMessage(), e);
  60. } catch (IOException e) {
  61. // TODO Auto-generated catch block
  62. logger.error(e.getMessage(), e);
  63. }
  64. }
  65. /**
  66. * 退出FTP登录关闭链接 并 关闭输入输出流
  67. *
  68. * @param
  69. */
  70. private void close() {
  71. try {
  72. if (is != null) {
  73. is.close();
  74. }
  75. if (os != null) {
  76. os.flush();
  77. os.close();
  78. }
  79. ftpClient.logout();
  80. logger.info("退出登录!");
  81. ftpClient.disconnect();
  82. logger.info("关闭链接!");
  83. } catch (IOException e) {
  84. // TODO Auto-generated catch block
  85. logger.error(e.getMessage(), e);
  86. }
  87. }
  88. /**
  89. * 判断是否是目录
  90. *
  91. * @param fileName
  92. * @return
  93. */
  94. public boolean isDir(String fileName) {
  95. try {
  96. // 切换目录,若当前是目录则返回true,否则返回true。
  97. boolean falg = ftpClient.changeWorkingDirectory(fileName);
  98. return falg;
  99. } catch (IOException e) {
  100. // TODO Auto-generated catch block
  101. logger.error(e.getMessage(), e);
  102. }
  103. return false;
  104. }
  105. /**
  106. * 上传文件
  107. *
  108. * @param exPath 自定义目录,默认空
  109. * @param extName 文件后缀名
  110. * @param in 文件输入流
  111. */
  112. public String defaultUpload(String exPath, String extName, FileInputStream in) {
  113. connect();
  114. String ftpPath;
  115. if (StringUtils.isNotEmpty(exPath)) {
  116. ftpPath = rootPath + exPath;
  117. } else {
  118. ftpPath = rootPath;
  119. }
  120. String fileName = IdUtil.createIdByTime() + "." + extName;
  121. boolean flag = uploadFileByDo(ftpPath, fileName, in);
  122. close();
  123. String url = null;
  124. if (flag) {
  125. url = httpAddr + ftpPath + "/" + fileName;
  126. }
  127. return url;
  128. }
  129. /**
  130. * 上传文件
  131. *
  132. * @param ftpPath
  133. * @param fileName
  134. */
  135. public boolean uploadFile(String ftpPath, String fileName, InputStream is) {
  136. connect();
  137. boolean flag = uploadFileByDo(ftpPath, fileName, is);
  138. close();
  139. return flag;
  140. }
  141. /**
  142. * 下载文件
  143. *
  144. * @param remoteFtpPath
  145. * @param localPath
  146. * @param fileName
  147. * @return
  148. */
  149. public boolean downloadFile(String remoteFtpPath, String localPath, String fileName) {
  150. connect();
  151. boolean flag = this.downloadFileByDo(remoteFtpPath, localPath, fileName);
  152. close();
  153. return flag;
  154. }
  155. /**
  156. * 删除ftp上的文件
  157. *
  158. * @param ftpFileName
  159. * @return true || false
  160. */
  161. public boolean removeFile(String ftpFileName) {
  162. boolean flag = false;
  163. logger.info("待删除文件:{0}"
  164. , ftpFileName);
  165. try {
  166. ftpFileName = new String(ftpFileName.getBytes("GBK"), "iso-8859-1");
  167. flag = ftpClient.deleteFile(ftpFileName);
  168. logger.info("删除文件:[{0}]"
  169. , flag ? "成功" : "失败");
  170. return flag;
  171. } catch (IOException e) {
  172. e.printStackTrace();
  173. return false;
  174. }
  175. }
  176. /**
  177. * 删除空目录
  178. *
  179. * @param dir
  180. * @return
  181. */
  182. public boolean removeDir(String dir) {
  183. if (StringUtils.startsWith(dir, "/"))
  184. dir = "/" + dir;
  185. try {
  186. String d = new String(dir.toString().getBytes("GBK"), "iso-8859-1");
  187. return ftpClient.removeDirectory(d);
  188. } catch (Exception e) {
  189. e.printStackTrace();
  190. return false;
  191. }
  192. }
  193. /**
  194. * 创建目录(有则切换目录,没有则创建目录)
  195. *
  196. * @param dir
  197. * @return
  198. */
  199. public boolean createDir(String dir) {
  200. if (StringUtils.isBlank(dir))
  201. return true;
  202. String d;
  203. try {
  204. //目录编码,解决中文路径问题
  205. d = new String(dir.toString().getBytes("GBK"), "iso-8859-1");
  206. //尝试切入目录
  207. if (ftpClient.changeWorkingDirectory(d))
  208. return true;
  209. String[] arr = dir.split("/");
  210. StringBuffer sbfDir = new StringBuffer();
  211. //循环生成子目录
  212. for (String s : arr) {
  213. sbfDir.append("/");
  214. sbfDir.append(s);
  215. //目录编码,解决中文路径问题
  216. d = new String(sbfDir.toString().getBytes("GBK"), "iso-8859-1");
  217. //尝试切入目录
  218. if (ftpClient.changeWorkingDirectory(d))
  219. continue;
  220. if (!ftpClient.makeDirectory(d)) {
  221. logger.info("[失败]ftp创建目录:" + sbfDir.toString());
  222. return false;
  223. }
  224. logger.info("[成功]创建ftp目录:" + sbfDir.toString());
  225. }
  226. //将目录切换至指定路径
  227. return ftpClient.changeWorkingDirectory(d);
  228. } catch (Exception e) {
  229. e.printStackTrace();
  230. return false;
  231. }
  232. }
  233. /**
  234. * 上传文件
  235. *
  236. * @param ftpPath FTP服务器保存目录
  237. * @param fileName 上传到FTP服务器上的文件名
  238. */
  239. private boolean uploadFileByDo(String ftpPath, String fileName, InputStream is) {
  240. try {
  241. if (!createDir(ftpPath)) {
  242. throw new RuntimeException("切入FTP目录失败:" + ftpPath);
  243. }
  244. ftpClient.setBufferSize(1024);
  245. //解决上传中文 txt 文件乱码
  246. ftpClient.setControlEncoding("utf-8");
  247. FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);
  248. conf.setServerLanguageCode("zh");
  249. // 设置文件类型(二进制)
  250. ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
  251. if (ftpClient.storeFile(fileName, is)) {
  252. is.close();
  253. return true;
  254. } else {
  255. logger.info("上传文件失败!");
  256. return false;
  257. }
  258. } catch (IOException e) {
  259. // TODO Auto-generated catch block
  260. logger.error(e.getMessage(), e);
  261. return false;
  262. } finally {
  263. try {
  264. if (is != null) {
  265. is.close();
  266. }
  267. } catch (IOException e) {
  268. // TODO Auto-generated catch block
  269. logger.error(e.getMessage(), e);
  270. }
  271. }
  272. }
  273. /**
  274. * 下载文件
  275. *
  276. * @param remoteFtpPath FTP服务器保存目录
  277. * localPath
  278. * @param fileName 上传到FTP服务器上的文件名
  279. */
  280. private boolean downloadFileByDo(String remoteFtpPath, String localPath, String fileName) {
  281. try {
  282. boolean changedir = ftpClient.changeWorkingDirectory(remoteFtpPath);
  283. if (!changedir) {
  284. logger.info("切入目录失败!");
  285. return false;
  286. }
  287. ftpClient.setBufferSize(1024);
  288. //解决上传中文 txt 文件乱码
  289. ftpClient.setControlEncoding("utf-8");
  290. FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);
  291. conf.setServerLanguageCode("zh");
  292. // 设置文件类型(二进制)
  293. ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
  294. FTPFile[] files = ftpClient.listFiles();
  295. for (int i = 0; i < files.length; i++) {
  296. try {
  297. if (fileName.equals(files[i].getName())) {
  298. downloadFile(files[i], localPath, remoteFtpPath);
  299. return true;
  300. }
  301. } catch (Exception e) {
  302. logger.error("下载异常", e);
  303. logger.error("<" + files[i].getName() + ">下载失败");
  304. }
  305. }
  306. } catch (IOException e) {
  307. // TODO Auto-generated catch block
  308. logger.error(e.getMessage(), e);
  309. return false;
  310. } finally {
  311. try {
  312. if (is != null) {
  313. is.close();
  314. }
  315. } catch (IOException e) {
  316. // TODO Auto-generated catch block
  317. logger.error(e.getMessage(), e);
  318. }
  319. }
  320. return true;
  321. }
  322. /**
  323. * 下载FTP文件
  324. * 当你需要下载FTP文件的时候,调用此方法
  325. * 根据<b>获取的文件名,本地地址,远程地址</b>进行下载
  326. *
  327. * @param ftpFile
  328. * @param relativeLocalPath
  329. * @param relativeRemotePath
  330. */
  331. private void downloadFile(FTPFile ftpFile, String relativeLocalPath, String relativeRemotePath) {
  332. if (ftpFile.isFile()) {
  333. if (ftpFile.getName().indexOf("?") == -1) {
  334. OutputStream outputStream = null;
  335. try {
  336. File entryDir = new File(relativeLocalPath);
  337. //如果文件夹路径不存在,则创建文件夹
  338. if (!entryDir.exists() || !entryDir.isDirectory()) {
  339. entryDir.mkdirs();
  340. }
  341. File locaFile = new File(relativeLocalPath + ftpFile.getName());
  342. //判断文件是否存在,存在则返回
  343. if (locaFile.exists()) {
  344. return;
  345. } else {
  346. outputStream = new FileOutputStream(relativeLocalPath + ftpFile.getName());
  347. ftpClient.retrieveFile(ftpFile.getName(), outputStream);
  348. outputStream.flush();
  349. outputStream.close();
  350. }
  351. } catch (Exception e) {
  352. logger.error("下载异常", e);
  353. } finally {
  354. try {
  355. if (outputStream != null) {
  356. outputStream.close();
  357. }
  358. } catch (IOException e) {
  359. logger.error("输出文件流异常");
  360. }
  361. }
  362. }
  363. } else {
  364. String newlocalRelatePath = relativeLocalPath + ftpFile.getName();
  365. String newRemote = new String(relativeRemotePath + ftpFile.getName().toString());
  366. File fl = new File(newlocalRelatePath);
  367. if (!fl.exists()) {
  368. fl.mkdirs();
  369. }
  370. try {
  371. newlocalRelatePath = newlocalRelatePath + '/';
  372. newRemote = newRemote + "/";
  373. String currentWorkDir = ftpFile.getName().toString();
  374. boolean changedir = ftpClient.changeWorkingDirectory(currentWorkDir);
  375. if (changedir) {
  376. FTPFile[] files = null;
  377. files = ftpClient.listFiles();
  378. for (int i = 0; i < files.length; i++) {
  379. downloadFile(files[i], newlocalRelatePath, newRemote);
  380. }
  381. }
  382. if (changedir) {
  383. ftpClient.changeToParentDirectory();
  384. }
  385. } catch (Exception e) {
  386. logger.error("下载异常", e);
  387. }
  388. }
  389. }
  390. /**
  391. * 下载文件
  392. *
  393. * @param remoteFtpPath FTP服务器保存目录
  394. * localPath
  395. * @param fileName 上传到FTP服务器上的文件名
  396. */
  397. public File getFtpFile(String remoteFtpPath, String fileName) {
  398. connect();
  399. File file = null;
  400. try {
  401. boolean changedir = ftpClient.changeWorkingDirectory(remoteFtpPath);
  402. if (!changedir) {
  403. logger.info("切入目录失败!");
  404. return file;
  405. }
  406. ftpClient.setBufferSize(1024);
  407. //解决上传中文 txt 文件乱码
  408. ftpClient.setControlEncoding("utf-8");
  409. FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);
  410. conf.setServerLanguageCode("zh");
  411. // 设置文件类型(二进制)
  412. ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
  413. FTPFile[] files = ftpClient.listFiles();
  414. for (int i = 0; i < files.length; i++) {
  415. try {
  416. if (fileName.equals(files[i].getName())) {
  417. InputStream fis = ftpClient.retrieveFileStream(files[i].getName());
  418. file = new File("drtext.xlsx");
  419. OutputStream os = new FileOutputStream(file);
  420. int bytesRead = 0;
  421. byte[] buffer = new byte[1024];
  422. while ((bytesRead = fis.read(buffer, 0, 1024)) != -1) {
  423. os.write(buffer, 0, bytesRead);
  424. }
  425. os.close();
  426. fis.close();
  427. return file;
  428. }
  429. } catch (Exception e) {
  430. logger.error("读取异常", e);
  431. }
  432. }
  433. close();
  434. } catch (IOException e) {
  435. // TODO Auto-generated catch block
  436. logger.error(e.getMessage(), e);
  437. } finally {
  438. try {
  439. if (is != null) {
  440. is.close();
  441. }
  442. } catch (IOException e) {
  443. // TODO Auto-generated catch block
  444. logger.error(e.getMessage(), e);
  445. }
  446. }
  447. return file;
  448. }
  449. public String getUserName() {
  450. return userName;
  451. }
  452. public void setUserName(String userName) {
  453. this.userName = userName;
  454. }
  455. public String getPassword() {
  456. return password;
  457. }
  458. public void setPassword(String password) {
  459. this.password = password;
  460. }
  461. public String getFtpHostName() {
  462. return ftpHostName;
  463. }
  464. public void setFtpHostName(String ftpHostName) {
  465. this.ftpHostName = ftpHostName;
  466. }
  467. public int getPort() {
  468. return port;
  469. }
  470. public void setPort(int port) {
  471. this.port = port;
  472. }
  473. public OutputStream getOs() {
  474. return os;
  475. }
  476. public void setOs(OutputStream os) {
  477. this.os = os;
  478. }
  479. /*public String uploadImage(String extPath, String extName, FileInputStream ins) {
  480. connect();
  481. String ftpPath;
  482. if (StringUtils.isNotEmpty(extPath)) {
  483. ftpPath = rootPath + extPath;
  484. } else {
  485. ftpPath = rootPath;
  486. }
  487. String fileName = IdUtil.createIdByTime() + "." + extName;
  488. boolean flag = uploadFileByDo(ftpPath, fileName, ins);
  489. close();
  490. String url = null;
  491. if (flag) {
  492. url = httpAddr + ftpPath + fileName;
  493. //FileUtil.del(tempFile);
  494. }
  495. return url;
  496. } catch (IOException e) {
  497. e.printStackTrace();
  498. return null;
  499. }
  500. }*/
  501. /**
  502. * 测试文件上传
  503. * 1.原目标文件流
  504. * 2.目标文件流
  505. */
  506. public String uploadImage(String extPath, String extName, File file) throws FileNotFoundException {
  507. connect();
  508. String ftpPath;
  509. if (StringUtils.isNotEmpty(extPath)) {
  510. ftpPath = rootPath + extPath;
  511. } else {
  512. ftpPath = rootPath;
  513. }
  514. System.out.println(file.length());
  515. FileInputStream ins = new FileInputStream(file);
  516. String fileName = IdUtil.createIdByTime() + "." + extName;
  517. File tempFile = FileUtil.writeFromStream(ins, tempDir + "/" + fileName);
  518. BufferedOutputStream out = FileUtil.getOutputStream(tempFile);
  519. try {
  520. //TODO 打水印
  521. ImgUtil.pressText(
  522. file, //
  523. tempFile,
  524. "赛轮版权所有", Color.WHITE, //文字
  525. new Font("黑体", Font.BOLD, 50), //字体
  526. 0, //x坐标修正值。 默认在中间,偏移量相对于中间偏移
  527. 0, //y坐标修正值。 默认在中间,偏移量相对于中间偏移
  528. 0.5f//透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字
  529. );
  530. //System.out.println(tempFile.length());
  531. boolean flag = uploadFileByDo(ftpPath, fileName, new FileInputStream(tempFile));
  532. close();
  533. String url = null;
  534. if (flag) {
  535. url = httpAddr + ftpPath + fileName;
  536. FileUtil.del(tempFile);
  537. //this.deleteAllFilesOfDir(tempFile);
  538. }
  539. return url;
  540. } catch (IOException e) {
  541. e.printStackTrace();
  542. return null;
  543. }
  544. }
  545. public String uploadImageForStram(String extPath, String extName, InputStream inputStream) throws FileNotFoundException {
  546. connect();
  547. String ftpPath;
  548. if (StringUtils.isNotEmpty(extPath)) {
  549. ftpPath = rootPath + extPath;
  550. } else {
  551. ftpPath = rootPath;
  552. }
  553. String fileName = IdUtil.createIdByTime() + "." + extName;
  554. File tempFile = FileUtil.writeFromStream(inputStream, tempDir + "/" + fileName);
  555. BufferedOutputStream out = FileUtil.getOutputStream(tempFile);
  556. try {
  557. //TODO 打水印
  558. ImgUtil.pressText(
  559. inputStream, //
  560. out,
  561. "赛轮版权所有", Color.WHITE, //文字
  562. new Font("黑体", Font.BOLD, 50), //字体
  563. 0, //x坐标修正值。 默认在中间,偏移量相对于中间偏移
  564. 0, //y坐标修正值。 默认在中间,偏移量相对于中间偏移
  565. 0.5f//透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字
  566. );
  567. //System.out.println(tempFile.length());
  568. boolean flag = uploadFileByDo(ftpPath, fileName, new FileInputStream(tempFile));
  569. close();
  570. String url = null;
  571. if (flag) {
  572. url = httpAddr + ftpPath + fileName;
  573. FileUtil.del(tempFile);
  574. //FileUtil.del(tempFile);
  575. //this.deleteAllFilesOfDir(tempFile);
  576. }
  577. return url;
  578. } catch (IOException e) {
  579. e.printStackTrace();
  580. return null;
  581. }
  582. }
  583. public static void deleteAllFilesOfDir(File path) {
  584. if (null != path) {
  585. if (!path.exists())
  586. return;
  587. if (path.isFile()) {
  588. boolean result = path.delete();
  589. int tryCount = 0;
  590. while (!result && tryCount++ < 10) {
  591. System.gc(); // 回收资源
  592. result = path.delete();
  593. }
  594. }
  595. File[] files = path.listFiles();
  596. if (null != files) {
  597. for (int i = 0; i < files.length; i++) {
  598. deleteAllFilesOfDir(files[i]);
  599. }
  600. }
  601. path.delete();
  602. }
  603. }
  604. }