通过xftp可以看到目标服务器上面的资源如下:
第一步:导入ftp依赖:
<dependency> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> <version>3.7</version> <!-- 使用最新版本 --> </dependency>
首先是通过原生代码来操作:
这里有个坑:如果是匿名登录,账号密码还是要的
下载文件操作:
import com.example.demo.test1.utils.FtpUtil; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class test8 { public static void main(String[] args) throws Exception { String server = "ftp.ncbi.nlm.nih.gov"; int port = 21; String username = "anonymous"; String password = "your_password"; FTPClient ftpClient = new FTPClient(); ftpClient.connect(server, port); ftpClient.login(username, password); String remoteFilePath = "/pubmed/updatefiles/pubmed24n1220.xml.gz"; String localFilePath = "D:\BaiduNetdiskDownload\pubmed24n1220.xml.gz"; //设置本地被动模式 ftpClient.enterLocalPassiveMode(); ftpClient.setControlEncoding("UTF-8"); // 设置二进制文件类型 //ftpClient.setFileType(org.apache.commons.net.ftp.FTP.BINARY_FILE_TYPE); try { // 创建本地文件输出流 OutputStream outputStream = new FileOutputStream(localFilePath); // 从 FTP 服务器下载文件 boolean success = ftpClient.retrieveFile(remoteFilePath, outputStream); if (success) { System.out.println("File downloaded successfully."); } else { System.out.println("File download failed."); } } catch (IOException e) { e.printStackTrace(); } finally { // 关闭 FTP 连接 ftpClient.logout(); ftpClient.disconnect(); } } }
这里的远端路径和需要下载的本地路径我都提前把文件名拼上去了,根据需要可以动态拼接:下载结果:
查看文件目录操作:查看/pubmed下的目录:
public class test6 { public static void main(String[] args) throws Exception{ String server = "ftp.ncbi.nlm.nih.gov"; int port = 21; String username = "anonymous"; String password = "your_password"; String remoteFilePath2 = "/pubmed"; FTPClient ftpClient = new FTPClient(); try { ftpClient.connect(server, port); ftpClient.login(username, password); // 设置本地被动模式 ftpClient.enterLocalPassiveMode(); // 设置二进制文件类型 ftpClient.setFileType(FTP.BINARY_FILE_TYPE); // 切换到指定文件夹 ftpClient.changeWorkingDirectory(remoteFilePath2); // 使用listDirectories()获取目录列表 FTPFile[] ftpDirectories = ftpClient.listDirectories(); if (ftpDirectories != null && ftpDirectories.length > 0) { System.out.println("子目录列表:"); for (FTPFile ftpDirectory : ftpDirectories) { System.out.println(ftpDirectory.getName()); } } else { System.out.println("当前文件夹中没有子目录。"); } } catch (IOException e) { e.printStackTrace(); } finally { try { // 关闭 FTP 连接 ftpClient.logout(); ftpClient.disconnect(); } catch (IOException e) { e.printStackTrace(); } } } }
查看目录下文件操作:查看/pubmed/updatefiles下的gz结尾文件
import com.example.demo.test1.utils.FtpUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; import java.io.*; @Slf4j public class test5 { public static void main(String[] args) throws Exception { FTPClient ftpClient = FtpUtil.getFtpClient("ftp.ncbi.nlm.nih.gov", 21, "anonymous", "your_password"); try { // 切换到指定文件夹 String remoteFolder = "/pubmed/updatefiles"; ftpClient.changeWorkingDirectory(remoteFolder); // 使用LIST命令获取详细文件列表 String[] fileDetails = ftpClient.listNames(); if (fileDetails != null && fileDetails.length > 0) { System.out.println("文件列表:"); for (String fileDetail : fileDetails) { if (fileDetail.endsWith(".gz")) { System.out.println(fileDetail); } } } else { System.out.println("文件夹为空或没有权限查看文件列表。"); } } catch (IOException e) { e.printStackTrace(); } finally { // 关闭 FTP 连接 FtpUtil.disConnect(ftpClient); } } }
这里的登录退出都是使用了FtpUtil工具类,方便很多,直接上工具类代码:
import lombok.extern.slf4j.Slf4j; import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPReply; import java.io.*; import java.nio.charset.StandardCharsets; @Slf4j public class FtpUtil { /** * 获取一个ftp连接 * @param host ip地址 * @param port 端口 * @param username 用户名 * @param password 密码 * @return 返回ftp连接对象 * @throws Exception 连接ftp时发生的各种异常 */ public static FTPClient getFtpClient(String host, Integer port, String username, String password) throws Exception{ FTPClient ftpClient = new FTPClient(); // 连接服务器 ftpClient.connect(host, port); int reply = ftpClient.getReplyCode(); if(!FTPReply.isPositiveCompletion(reply)){ log.error("无法连接至ftp服务器, host:{}, port:{}", host, port); ftpClient.disconnect(); return null; } // 登入服务器 boolean login = ftpClient.login(username, password); if(!login){ log.error("登录失败, 用户名或密码错误"); ftpClient.logout(); ftpClient.disconnect(); return null; } // 连接并且成功登陆ftp服务器 log.info("login success ftp server, host:{}, port:{}, user:{}", host, port, username); // 设置通道字符集, 要与服务端设置一致 ftpClient.setControlEncoding("UTF-8"); // 设置文件传输编码类型, 字节传输:BINARY_FILE_TYPE, 文本传输:ASCII_FILE_TYPE, 建议使用BINARY_FILE_TYPE进行文件传输 ftpClient.setFileType(FTP.BINARY_FILE_TYPE); // 动模式: enterLocalActiveMode(),被动模式: enterLocalPassiveMode(),一般选择被动模式 ftpClient.enterLocalPassiveMode(); // 切换目录 //ftpClient.changeWorkingDirectory("xxxx"); return ftpClient; } /** * 断开ftp连接 * @param ftpClient ftp连接客户端 */ public static void disConnect(FTPClient ftpClient){ if(ftpClient == null){ return; } try { log.info("断开ftp连接, host:{}, port:{}", ftpClient.getPassiveHost(), ftpClient.getPassivePort()); ftpClient.logout(); ftpClient.disconnect(); } catch (IOException e) { e.printStackTrace(); log.error("ftp连接断开异常, 请检查"); } } /** * 文件下载 * @param ftpClient ftp连接客户端 * @param path 文件路径 * @param fileName 文件名称 */ public static void download(FTPClient ftpClient, String path, String fileName) throws Exception { if(ftpClient == null || path == null || fileName == null){ return; } // 中文目录处理存在问题, 转化为ftp能够识别中文的字符集 String remotePath; try { remotePath = new String(path.getBytes(StandardCharsets.UTF_8), FTP.DEFAULT_CONTROL_ENCODING); } catch (UnsupportedEncodingException e) { remotePath = path; } InputStream inputStream = ftpClient.retrieveFileStream(remotePath); if (inputStream == null) { log.error("{}在ftp服务器中不存在,请检查", path); return; } FileOutputStream outputStream = new FileOutputStream(fileName); BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream); try{ byte[] buffer = new byte[2048]; int i; while ((i = bufferedInputStream.read(buffer)) != -1) { bufferedOutputStream.write(buffer, 0, i); bufferedOutputStream.flush(); } } catch (Exception e) { log.error("文件下载异常", e); log.error("{}下载异常,请检查", path); } inputStream.close(); outputStream.close(); bufferedInputStream.close(); bufferedOutputStream.close(); // 关闭流之后必须执行,否则下一个文件导致流为空 boolean complete = ftpClient.completePendingCommand(); if(complete){ log.info("文件{}下载完成", remotePath); }else{ log.error("文件{}下载失败", remotePath); } } /** * 上传文件 * @param ftpClient ftp连接客户端 * @param sourcePath 源地址 */ public static void upload(FTPClient ftpClient, String sourcePath) throws Exception{ if(ftpClient == null || sourcePath == null){ return; } File file = new File(sourcePath); if(!file.exists() || !file.isFile()){ return; } // 中文目录处理存在问题, 转化为ftp能够识别中文的字符集 String remotePath; try { remotePath = new String(file.getName().getBytes(StandardCharsets.UTF_8), FTP.DEFAULT_CONTROL_ENCODING); } catch (UnsupportedEncodingException e) { remotePath = file.getName(); } try( InputStream inputStream = new FileInputStream(file); OutputStream outputStream = ftpClient.storeFileStream(remotePath); ){ byte[] buffer = new byte[2048]; int length; while((length = inputStream.read(buffer)) != -1){ outputStream.write(buffer, 0, length); outputStream.flush(); } }catch (Exception e){ log.error("文件上传异常", e); } // 关闭流之后必须执行,否则下一个文件导致流为空 boolean complete = ftpClient.completePendingCommand(); if(complete){ log.info("文件{}上传完成", remotePath); }else{ log.error("文件{}上传失败", remotePath); } } }
参考链接:Java从ftp服务器上传与下载文件