java使用FTP

引入第三方java库

  • 使用apache 下的commons-net
  • commons-net api主页
//gradle形式引入 implementation 'commons-net:commons-net:3.6'//maven commons-net commons-net 3.6

主要api介绍
//连接 ftpClient.connect(hostName, port); //登录 ftpClient.login(username, password); //列出指定目录下的文件 ftpClient.listFiles(remotePath); // 上传文件 ftpClient.storeFile(remotePath, inputstream); //采用流的方式上传文件 ftpClient.storeFileStream(remotePath); //下载文件 ftpClient.retrieveFile(filename, outputStream); //流方式下载文件 ftpClient.retrieveFileStream(filename); // ftpClient命令执行的回调ftpClient所有的操作都是通过执行服务器命令来完成的,可通过该方式回调命令的执行 ftpClient.addProtocolCommandListener(new ProtocolCommandListener(){}); //命令操作, //可执行的命令封装在FTPCmd枚举类中, //操作CWD是cd ..的意思,也就是回到上层目录 ftpClient.doCommand(FTPCmd.CWD.getCommand(), "..");

初始化 连接到服务器
连接操作需要四个参数,分别是服务器ip,端口,用户名,密码
protected final boolean openConnect() { if (ftpClient == null) { ftpClient = new FTPClient(); } if (ftpClient.isConnected()) { return true; } // 中文转码 ftpClient.setControlEncoding("UTF-8"); int reply; // 连接至服务器 try { ftpClient.connect(hostName, port); } catch (IOException e) { onError("connect io error:" + e.getMessage()); return false; } // 获取响应值 reply = ftpClient.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { onError("connect fail: " + reply); return false; } // 登录到服务器 try { ftpClient.login(username, password); } catch (IOException e) { onError("login io error: " + e.getMessage()); return false; }// 获取响应值 reply = ftpClient.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { onError("login fail: " + reply); return false; }// 获取登录信息 try { FTPClientConfig config = new FTPClientConfig(ftpClient.getSystemType().split(" ")[0]); config.setServerLanguageCode("zh"); ftpClient.configure(config); // 使用被动模式设为默认 ftpClient.enterLocalPassiveMode(); // 二进制文件支持 ftpClient.setFileType(FTP.BINARY_FILE_TYPE); // 设置模式 ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE); } catch (IOException e) { onError("config io error: " + e.getMessage()); return false; }return true;

文件上传
【java使用FTP】文件上传分为文件上传和文件夹上传,多文件上传需要注意每次递归到内层工作目录做上传之后,应该恢复到上层目录 ,下载文件也一样
  • ftpClient.storeFile(remotePath, inputstream); 这种方式不能回调进度
  • ftpClient.storeFileStream(remotePath); 打开一个输出流用于写入到服务器,这种方式可以回调上传进度
/** * 上传. 流的方式 * * @param localFile本地文件 * @param remotePath FTP目录 * @return Result * @throws IOException */ public void upload(File localFile, String remotePath, IFtpListener listener) { setExecuteListener(listener); if (!openConnect()) { return; } // 改变FTP目录 try { ftpClient.changeWorkingDirectory(remotePath); // 获取上传前时间 if (localFile.isDirectory()) { // 上传多个文件 uploadMany(localFile); } else { // 上传单个文件 uploadSingle(localFile); } } catch (IOException e) { onError("upload: changeWorkingDirectory error"); return; } closeConnect(); }/** * 上传单个文件. * * @param localFile 本地文件 */ protected void uploadSingle(File localFile) throws IOException { final long totalSize = localFile.length(); final String filename = localFile.getName(); //开始 onStart(filename); InputStream inputStream = new FileInputStream(localFile); OutputStream outputStream = ftpClient.storeFileStream(filename); //从输入流写入到输出流 ioExecutor(filename, inputStream, outputStream, totalSize); //结束 onComplete(filename); }/** * 上传多个文件. * * @param localFile 本地文件夹 */ protected void uploadMany(@NotNull File localFile) throws IOException { if (!localFile.exists()) { onError("本地文件不存在: " + localFile.getAbsolutePath()); return; } // FTP下创建文件夹 final String childDir = localFile.getName(); ftpClient.makeDirectory(childDir); // 更改FTP目录 ftpClient.changeWorkingDirectory(childDir); // 得到当前目录下所有文件 File[] files = localFile.listFiles(); if (files == null) { onComplete(childDir); return; } // 遍历得到每个文件并上传 for (File file : files) { if (file.isHidden()) { continue; } if (file.isDirectory()) { // 上传多个文件 uploadMany(file); //切回到原来的目录 该操作是关键 ftpClient.doCommand(FTPCmd.CWD.getCommand(), ".."); } else { // 上传单个文件 uploadSingle(file); } } }

文件下载
文件下载分为单文件下载和文件夹下载,多文件上传需要注意每次递归到内层工作目录做上传之后,应该恢复到上层目录 ,下载文件也一样
  • ftpClient.retrieveFile(filename, outputStream); 这种方式不能回调进度
  • ftpClient.retrieveFileStream(filename); 打开一个输入流 读取服务器文件,这种方式可以回调上传进度
/** * 下载. * * @param remotePath FTP目录 * @param fileName文件名 * @param localPath本地目录 * @return Result * @throws IOException */ public void download(String remotePath, String fileName, String localPath, IFtpListener listener) { setExecuteListener(listener); if (!openConnect()) { return; } // 改变FTP目录 try { ftpClient.changeWorkingDirectory(remotePath); // 得到FTP当前目录下所有文件 FTPFile[] ftpFiles = ftpClient.listFiles(); // 循环遍历 FTPFile targetFile = null; for (FTPFile ftpFile : ftpFiles) { // 找到需要下载的文件 if (ftpFile.getName().equals(fileName)) { targetFile = ftpFile; break; } } if (targetFile == null) { onError("服务端文件不存在:" + remotePath + "/" + fileName); return; } // 创建本地目录 File file = new File(localPath + "/" + fileName); if (targetFile.isDirectory()) { // 下载多个文件 downloadMany(file, targetFile); } else { // 下载当个文件 downloadSingle(file, targetFile); } } catch (IOException e) { onError("download:" + e.getMessage()); } // 下载完时间 closeConnect(); }/** * 下载单个文件. * * @param localFile 本地目录 * @param ftpFileFTP目录 */ protected void downloadSingle(File localFile, FTPFile ftpFile) throws IOException { //文件总大小 final long totalSize = ftpFile.getSize(); final String filename = ftpFile.getName(); //开始 onStart(filename); // 创建输出流 OutputStream outputStream = new FileOutputStream(localFile); ftpClient.retrieveFile(filename, outputStream); InputStream inputStream = ftpClient.retrieveFileStream(filename); //从输入流写入到输出流并打印进度 ioExecutor(filename, inputStream, outputStream, totalSize); //结束 onComplete(filename); }/** * 下载多个文件. * * @param remoteFile 要下载的远程文件夹 */ protected void downloadMany(File localFile, FTPFile remoteFile) throws IOException { // 创建本地文件夹 if (!localFile.exists()) { if (!localFile.mkdirs()) { onError("创建本地文件失败: " + localFile.getAbsolutePath()); return; } } // 更改FTP当前目录 ftpClient.changeWorkingDirectory(remoteFile.getName()); // 得到FTP当前目录下所有文件 FTPFile[] ftpFiles = ftpClient.listFiles(); // 循环遍历 for (FTPFile ftpFile : ftpFiles) { // 创建文件 File file = new File(localFile.getAbsolutePath() + "/" + ftpFile.getName()); if (ftpFile.isDirectory()) { // 下载多个文件 downloadMany(file, ftpFile); // 返回到外层目录 ftpClient.doCommand(FTPCmd.CWD.getCommand(), ".."); } else { // 下载单个文件 downloadSingle(file, ftpFile); } } }

    推荐阅读