思路
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 | public static boolean (String middlePath, String fileName, String localPath) throws IOException { return downloadFromFtp(url, port, username, password,middlePath, fileName, localPath); } public static boolean (String url, int port, String username, String password, String path, String fileName, String localpath) throws IOException { boolean flag = false; FTPClient ftp = new FTPClient(); //设置超时时间以毫秒为单位使用时,从数据连接读。 ftp.setDefaultTimeout(timeOut * 1000); ftp.setConnectTimeout(timeOut * 1000); ftp.setDataTimeout(timeOut * 1000); ftp.setControlEncoding("utf-8");//此处设置为u8就不用转换编码格式了 int reply; try { if (port > -1) { ftp.connect(url, port); } else { ftp.connect(url);//ftp默认的端口是21 } //很多人写的是用ftp.getReplyCode()给获取连接的返回值,但是这样会导致storeFileStream返回null ftp.login(username, password); ftp.enterLocalActiveMode(); ftp.setFileType(FTPClient.BINARY_FILE_TYPE); reply = ftp.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftp.disconnect(); return flag; } //切换目录 此处可以判断,切换失败就说明ftp上面没有这个路径 ftp.changeWorkingDirectory(path); //上传文件 OutputStream out = null; InputStream in = null; //创建本地的文件时候要把编码格式转回来 File localDir = new File(localpath +"/" + path); if(!localDir.exists()){ localDir.mkdirs(); } File localFile = new File(localpath + "/" + path + "/" + fileName); out = new FileOutputStream(localFile); //ftp.enterLocalPassiveMode(); in = ftp.retrieveFileStream(fileName); byte[] byteArray = new byte[4096]; int read = 0; while ((read = in.read(byteArray)) != -1) { out.write(byteArray, 0, read); } //这句很重要 要多次操作这个ftp的流的通道,要等他的每次命令完成 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; } // 下载文件的具体业务 // ftpPath ftp地址(c:/ftp) // 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); // 调用ftp下载文件 FtpUtils.downloadFromFtp(middlePath,fileName,baseLocalPath); System.out.println(middlePath + fileName + "下载成功"); } 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"); // ftp的根目录 (c:/ftp) String ftpPath = "c:/FTP/"; String baseLocalPath = "/home/zyh/Documents/tmp4/"; fixedThreadPool.execute(new DownLoadThread(files,ftpPath,baseLocalPath)); fixedThreadPool.shutdown(); } } |