通过xftp可以看到目标服务器上面的资源如下:
第一步:导入ftp依赖:
<dependency><groupId>commons-net</groupId><artifactId>commons-net</artifactId><version>3.7</version> <!-- 使用最新版本 --></dependency>
首先是通过原生代码来操作:
这里有个坑:如果是匿名登录,账号密码还是要的String username = "anonymous"
即可,密码随意,直接上代码:
下载文件操作:
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服务器上传与下载文件