import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateUtils; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPReply; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ResourceLoaderAware; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.stereotype.Service; import java.io.*; import java.text.ParseException; import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; /** @Author Canaan @Date 2018/3/22 */ @Service public class ServiceImpl implements Service, ResourceLoaderAware { private final static String FTP_PASSWORD = "isddsdfc"; private final static String FTP_URL = "ls.csdrt.com.cn"; private final static String FTP_USER_NAME = "idsfsc"; private final static Integer FTP_PORT = 21; private final static String FTP_PATH = "cusdrwewnt/fosfsclock/"; //fpt目錄 private final static String FTP_ENCODING = "gbk"; // 歸檔的文件編碼 private final static String RESOURCE_FILE_DIR = "qefasd/current/foodclock/"; //下載路徑 private final static String LOCAL_FILE_PATH = "F:\\Downloads\\"; //本地路徑 private final Logger logger = LoggerFactory.getLogger(ServiceImpl.class); private Resource resource; @Override public void setResourceLoader(ResourceLoader resourceLoader) { resource = resourceLoader.getResource(RESOURCE_FILE_DIR); } /** 從ftp中下載歸檔<br> 測試下載時間: <li>6798 ms</li><li>6528 ms</li><li>6528 ms</li> <li>6523 ms</li><li>6554 ms</li><li>6479 ms</li> @return */ @Override public FamilyMartArchives downLoadFromFTP(Date date) throws IOException { FTPClient ftpClient = new FTPClient(); try { //1. 創建鏈接 ftpClient.connect(FTP_URL, FTP_PORT); //打開FTP服務器 //登陸 if (!ftpClient.login(FTP_USER_NAME, FTP_PASSWORD)) { logger.error("ftp登陸失敗"); return null; } int reply = ftpClient.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { logger.error("ftp is not positiveCompletion"); return null; } //目錄切換 if (!cd(ftpClient, FTP_PATH)) { logger.error("ftp目錄無效"); return null; } //文件預覽,沒有chk 文件就退出 String archivesFileName = null; //找出歸檔的文件 boolean flag = false; String[] names = ftpClient.listNames(); if (ArrayUtils.isEmpty(names)) { return null; } for (String name : names) { if (StringUtils.containsIgnoreCase(name, "FOODCLOCK") && StringUtils.containsIgnoreCase(name, ".zip")) { archivesFileName = name; } if (flag || StringUtils.containsIgnoreCase(name, ".chk")) { flag = true; } } if (!flag || StringUtils.isBlank(archivesFileName)) { logger.error("ftp歸檔失敗,沒有【.chk】文件"); return null; } //文件下載 Map<String, List<String>> archives; archives = loadFile(ftpClient, archivesFileName); if (archives == null || archives.isEmpty()) { return null; } //文件解析,返回歸檔文件 return analysis(archives); } finally { //關閉鏈接 closeFTP(ftpClient); } } /** 歸檔文件解析 @param archives @return */ private FamilyMartArchives analysis(Map<String, List<String>> archives) { // } /** 目錄切換 @param ftpClient @param path @return */ private boolean cd(FTPClient ftpClient, String path) { try { return ftpClient.changeWorkingDirectory(path); } catch (IOException e) { logger.error("切換目錄失敗【{}】", path, e); return false; } } /* 下載文件 */ private Map<String, List<String>> loadFile(FTPClient ftpClient, String archivesFileName) throws IOException { //TODO 若是本地文件已經存在,是否刪除? boolean flag = true; // 下載文件 BufferedOutputStream buffOut = null; try { //鎖的雙重驗證 if (resource != null && !resource.exists()) { synchronized (RESOURCE_FILE_DIR) { if (resource != null && !resource.exists()) { flag = resource.getFile().mkdirs(); } else { flag = true; } } } if (resource != null && flag) { buffOut = new BufferedOutputStream(new FileOutputStream(resource.getFile()+"\\"+ archivesFileName)); } else { buffOut = new BufferedOutputStream(new FileOutputStream(LOCAL_FILE_PATH + archivesFileName)); } flag = ftpClient.retrieveFile(archivesFileName, buffOut); } catch (Exception e) { logger.error("ftp文件下載失敗!", e); return null; } finally { try { if (buffOut != null) { buffOut.flush(); buffOut.close(); } } catch (Exception e) { // } } //文件解析 if(flag){ if (resource != null) { return readFile(resource.getFile().getPath()+"\\"+archivesFileName); } else { return readFile(LOCAL_FILE_PATH + archivesFileName); } } return null; } /** 讀取歸檔文件的內容 @return @throws IOException */ private Map<String, List<String>> readFile(String filePath) throws IOException { Map<String, List<String>> result = new HashMap<>(); ZipFile zf = new ZipFile(filePath); InputStream in = new BufferedInputStream(new FileInputStream(filePath)); ZipInputStream zin = new ZipInputStream(in); //ZipEntry 類用於表示 ZIP 文件條目。 ZipEntry ze; try { while ((ze = zin.getNextEntry()) != null) { if (ze.isDirectory()) { continue; } if (ze.getSize() <= 0) { continue; } List<String> rows = new ArrayList<>(); //記錄數 BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader(zf.getInputStream(ze), FTP_ENCODING)); String contextLine; while ((contextLine = reader.readLine()) != null) { rows.add(contextLine); } } finally { try { if (reader != null) { reader.close(); } } catch (IOException e) { // } } result.put(ze.getName(), rows); } } finally { try { if (zin != null) { zin.close(); } if (in != null) { in.close(); } if (zf != null) { zf.close(); } } catch (IOException e) { // } } return result; } }