package com.doumee.core.utils; import java.io.*; import java.net.MalformedURLException; import java.util.Date; import java.util.UUID; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.commons.net.PrintCommandListener; import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; import org.apache.commons.net.ftp.FTPReply; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; import org.apache.xpath.operations.Bool; import sun.misc.BASE64Encoder; /** */ /** * 支持断点续传的FTP实用类 * * @author BenZhou http://www.bt285.cn * @version 0.1 实现基本断点上传下载 * @version 0.2 实现上传下载进度汇报 * @version 0.3 实现中文目录创建及中文文件创建,添加对于中文的支持 */ @Slf4j public class FtpUtil { public FTPClient ftpClient = new FTPClient(); public static String hostname; public static int port; public static String username; public static String password; public FtpUtil() { // 设置将过程中使用到的命令输出到控制台 this.ftpClient.addProtocolCommandListener(new PrintCommandListener( new PrintWriter(System.out))); } public FtpUtil(String hostname, int port, String username, String password) throws IOException { // 设置将过程中使用到的命令输出到控制台 FtpUtil.hostname =hostname; FtpUtil.port =port; FtpUtil.username =username; FtpUtil.password =password; connect(); } /** * 初始化ftp服务器 */ public boolean connect() { boolean flag = false; try { System.out.println("connecting...ftp服务器:"+this.hostname+":"+this.port); ftpClient.setRemoteVerificationEnabled(false); ftpClient.connect(hostname, port); //连接ftp服务器 ftpClient.login(username, password); //登录ftp服务器 // if (FTPReply.isPositiveCompletion(ftpClient.sendCommand("OPTS UTF8", "ON"))) { // LOCAL_CHARSET = "UTF-8"; // } ftpClient.setControlEncoding("GBK"); ftpClient.enterLocalPassiveMode(); int replyCode = ftpClient.getReplyCode(); //是否成功登录服务器 if(!FTPReply.isPositiveCompletion(replyCode)){ log.error("connect failed...ftp服务器:"+this.hostname+":"+this.port+"返回码:"+replyCode); }else { flag = true; log.info("connect successful...ftp服务器:"+this.hostname+":"+this.port+"返回码:"+replyCode); } }catch (MalformedURLException e) { e.printStackTrace(); log.error("connect exception...ftp服务器:"+this.hostname+":"+this.port+ e.getMessage()); }catch (IOException e) { e.printStackTrace(); log.error("connect exception...ftp服务器:"+this.hostname+":"+this.port+ e.getMessage()); } return flag; } /** */ /** * 连接到FTP服务器 * * 密码 * @return 是否连接成功 * @throws IOException */ public boolean connect2() throws IOException { ftpClient.connect(hostname, port); ftpClient.setControlEncoding("GBK"); if (FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) { if (ftpClient.login(username, password)) { return true; } } disconnect(); return false; } /** */ /** * 从FTP服务器上下载文件,支持断点续传,上传百分比汇报 * * @param remote * 远程文件路径 * @param local * 本地文件路径 * @return 上传的状态 * @throws IOException */ public String download(String remote, String local) throws IOException { // 设置被动模式 ftpClient.enterLocalPassiveMode(); // 设置以二进制方式传输 ftpClient.setFileType(FTP.BINARY_FILE_TYPE); String result; // 检查远程文件是否存在 FTPFile[] files = ftpClient.listFiles(new String( remote.getBytes("GBK"), "iso-8859-1")); if (files.length != 1) { // System.out.println("远程文件不存在"); return "远程文件不存在"; } long lRemoteSize = files[0].getSize(); File f = new File(local); // 本地存在文件,进行断点下载 if (f.exists()) { long localSize = f.length(); // 判断本地文件大小是否大于远程文件大小 if (localSize >= lRemoteSize) { // System.out.println("本地文件大于远程文件,下载中止"); // return "本地文件大于远程文件,下载中止"; } // 进行断点续传,并记录状态 FileOutputStream out = new FileOutputStream(f, true); ftpClient.setRestartOffset(localSize); InputStream in = ftpClient.retrieveFileStream(new String(remote .getBytes("GBK"), "iso-8859-1")); byte[] bytes = new byte[1024]; long step = lRemoteSize / 100; long process = localSize / step; int c; while ((c = in.read(bytes)) != -1) { out.write(bytes, 0, c); localSize += c; long nowProcess = localSize / step; if (nowProcess > process) { process = nowProcess; if (process % 10 == 0) System.out.println("下载进度:" + process); // TODO 更新文件下载进度,值存放在process变量中 } } in.close(); out.close(); boolean isDo = ftpClient.completePendingCommand(); if (isDo) { result = "300"; // result = DownloadStatus.Download_From_Break_Success; } else { result = "400"; // result = DownloadStatus.Download_From_Break_Failed; } } else { OutputStream out = new FileOutputStream(f); InputStream in = ftpClient.retrieveFileStream(new String(remote .getBytes("GBK"), "iso-8859-1")); byte[] bytes = new byte[1024]; long step = lRemoteSize / 100; long process = 0; long localSize = 0L; int c; while ((c = in.read(bytes)) != -1) { out.write(bytes, 0, c); localSize += c; long nowProcess = localSize / step; if (nowProcess > process) { process = nowProcess; if (process % 10 == 0) System.out.println("下载进度:" + process); // TODO 更新文件下载进度,值存放在process变量中 } } in.close(); out.close(); boolean upNewStatus = ftpClient.completePendingCommand(); if (upNewStatus) { result = "500"; // result = DownloadStatus.Download_New_Success; } else { // result = DownloadStatus.Download_New_Failed; result = "600"; } } return result; } /** */ /** * 上传文件到FTP服务器,支持断点续传 * * @param local * 本地文件名称,绝对路径 * @param remote * 远程文件路径,使用/home/directory1/subdirectory/file.ext或是 * http://www.guihua.org /subdirectory/file.ext * 按照Linux上的路径指定方式,支持多级目录嵌套,支持递归创建不存在的目录结构 * @return 上传结果 * @throws IOException */ public String upload(String local, String remote) throws IOException { // 设置PassiveMode传输 ftpClient.enterLocalPassiveMode(); // 设置以二进制流的方式传输 ftpClient.setFileType(FTP.BINARY_FILE_TYPE); ftpClient.setControlEncoding("GBK"); String result; // 对远程目录的处理 String remoteFileName = remote; if (remote.contains(File.separator)) { remoteFileName = remote.substring(remote.lastIndexOf(File.separator) + 1); // 创建服务器远程目录结构,创建失败直接返回 if (StringUtils.equals(CreateDirecroty(remote, ftpClient), "2")) { return "2"; } } // 检查远程是否存在文件 FTPFile[] files = ftpClient.listFiles(new String(remoteFileName .getBytes("GBK"), "iso-8859-1")); if (files.length == 1) { long remoteSize = files[0].getSize(); File f = new File(local); long localSize = f.length(); if (remoteSize == localSize) { return "700"; // return UploadStatus.File_Exits; } else if (remoteSize > localSize) { return "800"; // return UploadStatus.Remote_Bigger_Local; } // 尝试移动文件内读取指针,实现断点续传 result = uploadFile(remoteFileName, f, ftpClient, remoteSize); // 如果断点续传没有成功,则删除服务器上文件,重新上传 if (StringUtils.equals(result, "1")) { if (!ftpClient.deleteFile(remoteFileName)) { return "1"; } result = uploadFile(remoteFileName, f, ftpClient, 0); } } else { result = uploadFile(remoteFileName, new File(local), ftpClient, 0); } return result; } public boolean uploadInputstream(InputStream inputStream, String remote) { // 设置PassiveMode传输 Date d1 = new Date(); log.error("上传文件成功=============开始========="+DateUtil.getPlusTime2(d1)); try { ftpClient.enterLocalPassiveMode(); // 设置以二进制流的方式传输 ftpClient.setFileType(FTP.BINARY_FILE_TYPE); ftpClient.setControlEncoding("GBK"); // 对远程目录的处理 String remoteFileName = remote; if (remote.contains("/")) { remoteFileName = remote.substring(remote.lastIndexOf("/") + 1); // 创建服务器远程目录结构,创建失败直接返回 if (StringUtils.equals(CreateDirecroty(remote, ftpClient), "2")) { log.error("创建ftp目录失败======================="+remote); return false; } } boolean result = ftpClient.storeFile(remoteFileName, inputStream); inputStream.close(); ftpClient.logout(); if(result){ log.info("上传文件成功======================"+remote); }else{ log.error("上传文件失败======================="+remote); } Date d2= new Date(); log.error("上传文件成功=============结束========="+DateUtil.getPlusTime2(d2) +"耗时毫秒:"+( (d2.getTime()-d1.getTime()) )); return result; }catch (Exception e){ e.printStackTrace(); log.error("上传文件失败======================="+remote); } return false; } public boolean uploadInputstreamBatch(InputStream inputStream, String remote, Boolean close , Integer index ) { // 设置PassiveMode传输 try { ftpClient.enterLocalPassiveMode(); // 设置以二进制流的方式传输 ftpClient.setFileType(FTP.BINARY_FILE_TYPE); ftpClient.setControlEncoding("GBK"); // 对远程目录的处理 String remoteFileName = remote; if (remote.contains("/")) { remoteFileName = remote.substring(remote.lastIndexOf("/") + 1); // 创建服务器远程目录结构,创建失败直接返回 if (Constants.equalsInteger(index,Constants.ONE) && StringUtils.equals(CreateDirecroty(remote, ftpClient), "2")) { log.error("创建ftp目录失败======================="+remote); return false; } } boolean result = ftpClient.storeFile(remoteFileName, inputStream); inputStream.close(); if(close){ ftpClient.logout(); } if(result){ log.info("上传文件成功======================"+remote); }else{ log.error("上传文件失败======================="+remote); } return result; }catch (Exception e){ e.printStackTrace(); log.error("上传文件失败======================="+remote); } return false; } public int getNumFromStr(String str,char searchstr) { int count = 0; char[] charArray = str.toCharArray(); for (char param : charArray) { if (param == searchstr) { count++; } } return count; } /** */ /** * 上传文件到FTP服务器,支持断点续传 * * @param localFile * 本地文件流 * @param remote * 远程文件路径,使用/home/directory1/subdirectory/file.ext或是 * http://www.guihua.org /subdirectory/file.ext * 按照Linux上的路径指定方式,支持多级目录嵌套,支持递归创建不存在的目录结构 * @return 上传结果 * @throws IOException */ public String uploadFile(File localFile, String remote) throws IOException { // 设置PassiveMode传输 ftpClient.enterLocalPassiveMode(); // 设置以二进制流的方式传输 ftpClient.setFileType(FTP.BINARY_FILE_TYPE); ftpClient.setControlEncoding("GBK"); String result; // 对远程目录的处理 String remoteFileName = remote ; if (remote.contains("/")) { remoteFileName = remote.substring(remote.lastIndexOf("/") + 1); // 创建服务器远程目录结构,创建失败直接返回 if (StringUtils.equals(CreateDirecroty(remote, ftpClient), "2")) { return "2"; } } // 检查远程是否存在文件 FTPFile[] files = ftpClient.listFiles(new String(remoteFileName .getBytes("GBK"), "iso-8859-1")); if (files.length == 1) { long remoteSize = files[0].getSize(); long localSize = localFile.length(); if (remoteSize == localSize) { return "700"; // return UploadStatus.File_Exits; } else if (remoteSize > localSize) { return "800"; // return UploadStatus.Remote_Bigger_Local; } // 尝试移动文件内读取指针,实现断点续传 result = uploadFile(remoteFileName, localFile, ftpClient, remoteSize); // 如果断点续传没有成功,则删除服务器上文件,重新上传 if (StringUtils.equals(result, "1")) { if (!ftpClient.deleteFile(remoteFileName)) { return "1"; } result = uploadFile(remoteFileName, localFile, ftpClient, 0); } // if (result == UploadStatus.Upload_From_Break_Failed) { // if (!ftpClient.deleteFile(remoteFileName)) { // return UploadStatus.Delete_Remote_Faild; // } // result = uploadFile(remoteFileName, f, ftpClient, 0); // } } else { result = uploadFile(remoteFileName, localFile, ftpClient, 0); } return result; } /** */ /** * 断开与远程服务器的连接 * * @throws IOException */ public void disconnect() throws IOException { if (ftpClient.isConnected()) { ftpClient.disconnect(); } } /** */ /** * 递归创建远程服务器目录 * * @param remote * 远程服务器文件绝对路径 * @param ftpClient * FTPClient对象 * @return 目录创建是否成功 * @throws IOException */ public String CreateDirecroty(String remote, FTPClient ftpClient) throws IOException { String status = "1"; // UploadStatus status = UploadStatus.Create_Directory_Success; String directory = remote.substring(0, remote.lastIndexOf("/") + 1); if (!directory.equalsIgnoreCase("/") && !ftpClient.changeWorkingDirectory(new String(directory .getBytes("GBK"), "iso-8859-1"))) { // 如果远程目录不存在,则递归创建远程服务器目录 int start = 0; int end = 0; if (directory.startsWith("/")) { start = 1; } else { start = 0; } end = directory .indexOf("/", start); while (true) { String subDirectory = new String(remote.substring(start, end) .getBytes("GBK"), "iso-8859-1"); if (!ftpClient.changeWorkingDirectory(subDirectory)) { if (ftpClient.makeDirectory(subDirectory)) { ftpClient.changeWorkingDirectory(subDirectory); } else { System.out.println("创建目录失败"); return "2"; // return UploadStatus.Create_Directory_Fail; } } start = end + 1; end = directory.indexOf("/", start); // 检查所有目录是否创建完毕 if (end <= start) { break; } } } return status; } /** * 上传文件到服务器,新上传和断点续传 * * @param remoteFile * 远程文件名,在上传之前已经将服务器工作目录做了改变 * @param localFile * 本地文件File句柄,绝对路径 * 需要显示的处理进度步进值 * @param ftpClient * FTPClient引用 * @return * @throws IOException */ public String uploadFile(String remoteFile, File localFile, FTPClient ftpClient, long remoteSize) throws IOException { String status; // 显示进度的上传 long step = localFile.length() / 100; step=step ==0?1:step; long process = 0; long localreadbytes = 0L; // System.out.println(remoteFile +"-------------------------"+localFile.getPath().toString()); RandomAccessFile raf = new RandomAccessFile(localFile, "r"); OutputStream out = ftpClient.appendFileStream(new String(remoteFile .getBytes("GBK"), "iso-8859-1")); // 断点续传 if (remoteSize > 0) { ftpClient.setRestartOffset(remoteSize); process = remoteSize / step; raf.seek(remoteSize); localreadbytes = remoteSize; } byte[] bytes = new byte[1024]; int c; while ((c = raf.read(bytes)) != -1) { out.write(bytes, 0, c); localreadbytes += c; if (localreadbytes / step != process) { process = localreadbytes / step; System.out.println("上传进度:" + process); // TODO 汇报上传状态 } } out.flush(); raf.close(); out.close(); boolean result = ftpClient.completePendingCommand(); if (remoteSize > 0) { status = result ? "0" : "1"; // status = result ? UploadStatus.Upload_From_Break_Success // : UploadStatus.Upload_From_Break_Failed; } else { status = result ? "0" : "1"; // status = result ? UploadStatus.Upload_New_File_Success // : UploadStatus.Upload_New_File_Failed; } return status; } public byte[] getOnlineInputsteam(String url){ try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) { HttpGet httpGet = new HttpGet(url); CloseableHttpResponse resp = httpClient.execute(httpGet);// 调用服务器接口 // return resp.getEntity().getContent(); byte[] data = EntityUtils.toByteArray(resp.getEntity());// 将返回的图片或者文件转化成字节数组的形式 // BASE64Encoder encoder = new BASE64Encoder(); // String imageBase64 = encoder.encode(data); // String imageBase64 = "data:image/jpg;base64," + encoder.encodeBuffer(data).trim(); // imageBase64 = imageBase64.replaceAll("\n", "").replaceAll("\r", "").replaceAll(" ", "");//删除 \r\n return data; } catch (Exception e) { log.error("获取图片异常:{}",e.getMessage()); } return null; } public boolean uploadOnlineFile(String url,String ftpPath, String fileName) throws Exception { byte[] buf = getOnlineInputsteam(url); if(buf == null){ return false; } try { ftpClient.enterLocalPassiveMode();// 开启被动模式 ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); CreateDirecroty( ftpPath,ftpClient); String printWorkingDirectory = ftpClient.printWorkingDirectory(); System.out.println("获取当前目录:" + printWorkingDirectory); boolean flag = ftpClient.storeFile(new String(fileName.getBytes("GBK"), "iso-8859-1"), new ByteArrayInputStream(buf)); // 通过发送 QUIT 命令注销 FTP 服务器 ftpClient.logout(); return flag; } catch (Exception e) { e.printStackTrace(); } finally { if (ftpClient.isConnected()){ ftpClient.disconnect(); } } return false; } /** * 删除一个文件 */ public boolean deleteFile(String filename) { boolean flag = true; try { flag = ftpClient.deleteFile(filename); if (flag) { System.out.println("删除文件成功!"); } else { System.out.println("删除文件失败!"); } } catch (IOException ioe) { ioe.printStackTrace(); } return flag; } public static void main(String[] args) throws Exception { try { FtpUtil ftpUtil = new FtpUtil("175.27.187.84", 21, "ftpuser","doumee168" ); ftpUtil.uploadOnlineFile("https://profile-avatar.csdnimg.cn/default.jpg!1", "test"+"/", UUID.randomUUID().toString()+"test.jpg"); /*FtpUtil myFtp = new FtpUtil("106.15.54.228", 21, "ftptlg", "tlg168.com"); System.out.println(myFtp.upload("D:\\devices.sql", "/1111/devices.sql")); // myFtp.ftpClient.makeDirectory(new String("电视剧".getBytes("GBK"), // "iso-8859-1")); // myFtp.ftpClient.changeWorkingDirectory(new String("电视剧" // .getBytes("GBK"), "iso-8859-1")); // myFtp.ftpClient.makeDirectory(new String("走西口".getBytes("GBK"), // "iso-8859-1")); // System.out.println(myFtp.upload("http://www.5a520.cn /yw.flv", // "/yw.flv", 5)); // System.out.println(myFtp.upload("http://www.5a520.cn /走西口24.mp4", // "/央视走西口/新浪网/走西口24.mp4")); *//** * t.connect("pengtu", "61.191.61.226", 2122, "yangnet", * "yanglong@doumee.com"); File file = new File( * "D:\\lib/commons-net-3.3-bin/commons-net-3.3/NOTICE.txt"); * * *//* System.out.println(myFtp.download("/1/2/NOTICE.txt", "D:\\哈.txt")); myFtp.deleteFile("/1/2/NOTICE.txt"); myFtp.disconnect(); System.out.println("java版本号:" + System.getProperty("java.version")); // java版本号 System.out .println("Java提供商名称:" + System.getProperty("java.vendor")); // Java提供商名称 System.out.println("Java提供商网站:" + System.getProperty("java.vendor.url")); // Java提供商网站 System.out.println("jre目录:" + System.getProperty("java.home")); // Java,哦,应该是jre目录 System.out.println("Java虚拟机规范版本号:" + System.getProperty("java.vm.specification.version")); // Java虚拟机规范版本号 System.out.println("Java虚拟机规范提供商:" + System.getProperty("java.vm.specification.vendor")); // Java虚拟机规范提供商 System.out.println("Java虚拟机规范名称:" + System.getProperty("java.vm.specification.name")); // Java虚拟机规范名称 System.out.println("Java虚拟机版本号:" + System.getProperty("java.vm.version")); // Java虚拟机版本号 System.out.println("Java虚拟机提供商:" + System.getProperty("java.vm.vendor")); // Java虚拟机提供商 System.out.println("Java虚拟机名称:" + System.getProperty("java.vm.name")); // Java虚拟机名称 System.out.println("Java规范版本号:" + System.getProperty("java.specification.version")); // Java规范版本号 System.out.println("Java规范提供商:" + System.getProperty("java.specification.vendor")); // Java规范提供商 System.out.println("Java规范名称:" + System.getProperty("java.specification.name")); // Java规范名称 System.out.println("Java类版本号:" + System.getProperty("java.class.version")); // Java类版本号 System.out.println("Java类路径:" + System.getProperty("java.class.path")); // Java类路径 System.out.println("Java lib路径:" + System.getProperty("java.library.path")); // Java lib路径 System.out.println("Java输入输出临时路径:" + System.getProperty("java.io.tmpdir")); // Java输入输出临时路径 System.out .println("Java编译器:" + System.getProperty("java.compiler")); // Java编译器 System.out.println("Java执行路径:" + System.getProperty("java.ext.dirs")); // Java执行路径 System.out.println("操作系统名称:" + System.getProperty("os.name")); // 操作系统名称 System.out.println("操作系统的架构:" + System.getProperty("os.arch")); // 操作系统的架构 System.out.println("操作系统版本号:" + System.getProperty("os.version")); // 操作系统版本号 System.out.println("文件分隔符:" + System.getProperty("file.separator")); // 文件分隔符 System.out.println("路径分隔符:" + System.getProperty("path.separator")); // 路径分隔符 System.out.println("直线分隔符:" + System.getProperty("line.separator")); // 直线分隔符 System.out.println("操作系统用户名:" + System.getProperty("user.name")); // 用户名 System.out.println("操作系统用户的主目录:" + System.getProperty("user.home")); // 用户的主目录 System.out.println("当前程序所在目录:" + System.getProperty("user.dir")); // 当前程序所在目录*/ } catch (IOException e) { System.out.println("连接FTP出错:" + e.getMessage()); } } /*** * @上传文件夹 * @param localDirectory * 当地文件夹 * @param remoteDirectoryPath * Ftp 服务器路径 以目录File.separator结束 * */ public boolean uploadDirectory(String localDirectory, String remoteDirectoryPath) throws Exception { File src = new File(localDirectory); try { remoteDirectoryPath = remoteDirectoryPath + "/"; boolean makeDirFlag = this.ftpClient.makeDirectory(remoteDirectoryPath); }catch (IOException e) { e.printStackTrace(); log.info(remoteDirectoryPath + "目录创建失败"); return false; } File[] allFile = src.listFiles(); for (int currentFile = 0;currentFile < allFile.length;currentFile++) { File f =allFile[currentFile]; String srcName= f.getPath().toString(); String tPath = remoteDirectoryPath+f.getName(); if (!f.isDirectory()) { int dNum = getNumFromStr(tPath,"/".toCharArray()[0]); uploadFile(f, tPath); if(dNum -2>=0){ for (int i = 0; i < dNum-1; i++) { this.ftpClient.changeToParentDirectory(); } } }else{ uploadDirectory(srcName, tPath+"/"); } } return true; } /*** * @上传文件夹 * @param pathName * 文件夹 * */ public boolean delDirectory(String pathName ) throws Exception { try { this.ftpClient.changeWorkingDirectory( pathName.substring(0, pathName.lastIndexOf("/")) ); ftpClient.removeDirectory(pathName); }catch (IOException e) { e.printStackTrace(); log.info(pathName + "目录删除失败"); return false; } return true; } }