最近接到个业务需要使用FTP拉取服务器上数据。要求可以任意指定下载对应目录数据,并且目录结构保持要。处理的数据文件特点分散而且很大。处理的思路大概有两个,一个是在服务端压缩成zip,然后传过来。二是使用多线程单个单个文件传输。在这里我使用的是第二中方法。
思路
1.服务端提供一个返回指定文件下的List<String> files
2.客户端拿到files文件列表,遍历单个单个文件请求服务端拉取数据
FTP下载使用
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
| public static boolean downloadFromFtp(String middlePath, String fileName, String localPath) throws IOException {
return downloadFromFtp(url, port, username, password,middlePath, fileName, localPath); }
public static boolean downloadFromFtp(String url, int port, String username, String password, String path, String fileName, String localpath) throws IOException { boolean flag = false; FTPClient ftp = new FTPClient(); int reply; try { if (port > -1) { ftp.connect(url, port); } else { ftp.connect(url); } ftp.login(username, password); ftp.enterLocalActiveMode(); ftp.setFileType(FTPClient.BINARY_FILE_TYPE); reply = ftp.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftp.disconnect(); return flag; } ftp.changeWorkingDirectory(path); OutputStream out = null; InputStream in = null; File localDir = new File(localpath +"/" + path); if(!localDir.exists()){ localDir.mkdirs(); } fileName = new String(fileName.getBytes("ISO-8859-1"), "utf-8"); File localFile = new File(localpath + "/" + path + "/" + fileName); out = new FileOutputStream(localFile); in = ftp.retrieveFileStream(fileName); byte[] byteArray = new byte[4096]; int read = 0; while ((read = in.read(byteArray)) != -1) { out.write(byteArray, 0, read); } ftp.completePendingCommand(); out.flush(); out.close(); ftp.logout(); flag = true; } catch (Exception e) { e.printStackTrace(); } finally { if (ftp.isConnected()) { ftp.disconnect(); } } return flag; }
|
downloadFromFtp传入参数说明String
参数 |
解释 |
url |
ftp的ip地址 |
port |
ftp的端口(默认21) |
usernameport |
ftp用户名 |
password |
ftp密码 |
path |
特别重要,一开报输入流为null就是因为它写错了;假如你的ftp根目录为C:/ftp/,你想要下载C:/ftp/xxx/下的文件,那么path就要写xxx/ |
fileName |
下载文件的名称 |
localpath |
下载到本地的路径 |
server返回制定文件列表
用户给定一个path,查处path下所有的文件,放在list,以json形式返回。
1 2 3 4 5 6 7 8 9 10 11 12 13
| public ArrayList listFiles(String path,ArrayList files){ File directory = new File(path); File[] currentFiles = directory.listFiles(); for (File file:currentFiles) { if (file.isDirectory()){ listFiles(file.getPath(),files); }else{ files.add(file); } } return files; }
|
client获取返回列表下载文件
四类线程池基本的线程池概述,这边按需求选择,我这里选了定长线程池FixedThreadPool
- FixedThreadPool 定长的线程池,初始化时指定线程的个数,当线程池中线程被用完时,其他任务阻塞等待
- CachedThreadPool 不定长线程池,无限扩大的线程池,来几个任务分配几个线程。
- SimpleThreadPool 单例线程,底层采用LinkedBlockQueue实现,除了排在队列最前面的线程以外的其他线程都要等着。
- ScheduleThreadPol 在初始化时可以指定时间帮助我们处理延时任务和定时任务。
客户端的思路:
1.使用HttpClient从后台发送请求获取待下载files列表
2.将DownloadThread分配给FixedThreadPool运行
这边主要看DownloadThread.java如何编写,以及如何分配给fixedThreadPool
DownloadThread.java
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
| package com.bim.task;
import com.bim.common.FtpUtils;
import java.util.List;
public class DownLoadThread implements Runnable {
List files = null; String ftpPath = null; String baseLocalPath = null;
public DownLoadThread(List files,String ftpPath,String baseLocalPath){ this.files = files; this.ftpPath = ftpPath; this.baseLocalPath = baseLocalPath; }
private void downloadFile(String file,String ftpPath,String baseLocalPath) throws Exception{ String dllPath = file.toString().replaceAll("\\\\","/"); int lastIndexOf = dllPath.lastIndexOf("/"); String middlePath = "/"; if(ftpPath.length() - 1 <= lastIndexOf){ middlePath = dllPath.substring(ftpPath.length(),lastIndexOf+1); } String fileName = dllPath.substring(lastIndexOf + 1,dllPath.length()); System.out.println("filename" + fileName); System.out.println("baseLocalPath" + baseLocalPath); System.out.println("开始下载:" + middlePath + fileName + "到本地" + baseLocalPath); FtpUtils.downloadFromFtp(middlePath,fileName,baseLocalPath); System.out.println(middlePath + fileName + "下载成功");
} @Override public void run() { try{ while(!files.isEmpty()){ String file = null; synchronized(files){ file = (String) files.get(0); files.remove(0); } downloadFile(file,ftpPath,baseLocalPath); } }catch (Exception e){ e.printStackTrace(); } } }
|
主程序拿到files后的逻辑代码部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class PullFileClient { private static ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10); public static void main(String[] args) throws IOException {
Map<String,Object> resultMap = client.sendGet(requestUrl); Object code = resultMap.get("code"); List files = (List) resultMap.get("data"); String ftpPath = "c:/FTP/"; String baseLocalPath = "/home/zyh/Documents/tmp4/"; fixedThreadPool.execute(new DownLoadThread(files,ftpPath,baseLocalPath)); fixedThreadPool.shutdown(); } }
|