FTP系列:
在Windows系统上搭建FTP服务器全面总结:https://blog.csdn.net/haoranhaoshi/article/details/86092630
FTP操作:https://blog.csdn.net/haoranhaoshi/article/details/86922363
FTP的Java操作全面实战:https://blog.csdn.net/haoranhaoshi/article/details/86922503
项目下载:https://download.csdn.net/download/haoranhaoshi/10952856
package ftptest;
public class FTPTest {
public static void main(String[] args) {
Ftp ftp = new Ftp();
ftp.setIpAddr("192.168.1.10");
ftp.setPort(21);
ftp.setUserName("testUser");
ftp.setPwd("Ty@123Ty");
FtpUtil ftpUtil = new FtpUtil();
try {
// 连接FTP
if (ftpUtil.connectFtp(ftp)) {
System.out.println("FTP连接成功");
System.out.println("----------------------------------------------");
// 传入当前工作目录的子路径,改变服务端工作目录,根目录下有无/皆可,/ftpTest/ftpTest1等同于ftpTest/ftpTest1
if (!ftpUtil.changeWorkingDirectory("/ftpTest/ftpTest1")) {
System.out.println("服务端路径错误");
}
// 得到当前服务端工作目录
System.out.println("当前服务端工作目录" + ftpUtil.getWorkingDirectory());
System.out.println("----------------------------------------------");
// 得到当前工作目录下的所有文件夹和文件名
System.out.println("-------当前工作目录下的所有文件夹和文件-------");
for (String fileName : ftpUtil.getWorkingDirectoryFileNames()) {
System.out.println(fileName);
}
// 上传文件夹及其所有子文件夹或文件,合并相同目录,文件替换
String uploadClientPath1 = "C:/Users/hao/Desktop/试试";
String uploadServerPath1 = "/ftpTest";
System.out.println("上传文件夹:" + uploadClientPath1 + ",到" + uploadServerPath1 + "," + (ftpUtil.upload(uploadServerPath1, uploadClientPath1, false, true) ? "成功" : "失败"));
// 上传文件,已经存在会替换
String uploadClientPath2 = "C:/Users/hao/Desktop/ftpTest1.txt";
String uploadServerPath2 = "/";
System.out.println("上传文件:" + uploadClientPath2 + ",到" + uploadServerPath2 + "," + (ftpUtil.upload(uploadServerPath2, uploadClientPath2, true, true) ? "成功" : "失败"));
// 下载文件夹及其所有子文件和文件夹,已存在则删除重建
String downloadServerPath1 = "/ftpTest";
String downloadClientPath1 = "C:/Users/hao/Desktop";
System.out.println("下载文件:" + downloadServerPath1 + ",到" + downloadClientPath1 + "," + (ftpUtil.downloadFile(downloadServerPath1, downloadClientPath1) ? "成功" : "失败"));
// 下载文件,已存在则删除重建
String downloadServerPath2 = "/ftpTest2.txt";
String downloadClientPath2 = "C:/Users/hao/Desktop";
System.out.println("下载文件:" + downloadServerPath2 + ",到" + downloadClientPath2 + "," + (ftpUtil.downloadFile(downloadServerPath2, downloadClientPath2) ? "成功" : "失败"));
} else {
System.out.println("FTP连接失败");
}
} catch (Exception e) {
e.printStackTrace();
}
ftpUtil.closeFtp();
}
}
package ftptest;
import java.io.*;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
/**
* Ftp工具类 需要导入commons-net-3.6.jar这个包
*/
public class FtpUtil {
private FTPClient ftpClient;
/**
* 本地字符编码
*/
private static String CLIENT_CHARSET = "GBK";
/**
* FTP协议里面,规定文件名编码为ISO-8859-1
*/
private static String SERVER_CHARSET = "ISO-8859-1";
/**
* 获取ftp连接
*
* @param ftp
* @return
* @throws Exception
*/
public boolean connectFtp(Ftp ftp) throws Exception {
ftpClient = new FTPClient();
boolean flag = true;
int reply;
try {
ftpClient.connect(ftp.getIpAddr(), ftp.getPort());
// ftp登陆
if (ftpClient.login(ftp.getUserName(), ftp.getPwd())) {
return false;
}
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码,否则就使用本地编码(GBK)
if (FTPReply.isPositiveCompletion(ftpClient.sendCommand("OPTS UTF8", "ON"))) {
CLIENT_CHARSET = "UTF-8";
}
ftpClient.setControlEncoding(CLIENT_CHARSET);
// 设置被动模式
ftpClient.enterLocalPassiveMode();
// 设置文件传输类型
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
// 检查延时
reply = ftpClient.getReplyCode();
// 如果延时不在200到300之间,就关闭连接
if (!FTPReply.isPositiveCompletion(reply)) {
ftpClient.disconnect();
flag = false;
}
} catch (Exception e) {
flag = false;
throw new Exception(e.getMessage());
} finally {
return flag;
}
}
/**
* 关闭ftp连接
*/
public void closeFtp() {
if (ftpClient != null && ftpClient.isConnected()) {
try {
ftpClient.logout();
ftpClient.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 传入服务端从根目录开始的完整文件路径,改变当前服务端工作目录
*/
public boolean changeWorkingDirectory(String serverPath) {
try {
while (!this.getWorkingDirectory().equals("/")) {
ftpClient.changeToParentDirectory();
}
return ftpClient.changeWorkingDirectory(clientCharsetToServer(serverPath));
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
/**
* 客户端编码转成FTP协议编码,防止中文路径在服务端无法识别
*
* @param dirName 客户端GBK或者UTF-8编码
*/
private String clientCharsetToServer(String dirName) {
try {
return new String(dirName.getBytes(CLIENT_CHARSET), SERVER_CHARSET);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return dirName;
}
}
/**
* FTP协议编码转成客户端编码,防止服务端中文路径乱码
*
* @param dirName 服务端FTP协议ISO-8859-1编码
*/
private String serverCharsetToClient(String dirName) {
try {
return new String(dirName.getBytes(SERVER_CHARSET), CLIENT_CHARSET);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return dirName;
}
}
/**
* 得到当前服务端工作目录
*/
public String getWorkingDirectory() {
try {
return serverCharsetToClient(ftpClient.printWorkingDirectory());
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
/**
* 上传文件或文件夹
*
* @param serverDirPath 服务端路径
* @param clientFilePath 客户端文件路径
* @param isCoverDirectory 文件夹已存在是否覆盖,是则删除重建,否则不删
* @param isCoverFile 文件已存在是否覆盖,是则删除重建,否则不删
* @throws Exception
*/
public boolean upload(String serverDirPath, String clientFilePath, boolean isCoverDirectory, boolean isCoverFile) throws Exception {
System.out.println("------------------上传文件--------------------");
if (serverDirPath != null) {
if (!this.changeWorkingDirectory(serverDirPath)) {
System.out.println("服务端路径错误");
return false;
}
}
System.out.println("当前服务端工作目录:" + getWorkingDirectory());
File file = new File(clientFilePath);
// 防止中文目录创建失败或者中文名的文件上传失败
String currentFileName = clientCharsetToServer(file.getName());
if (file.isDirectory()) {
if (isWorkingDirectoryHasFile(currentFileName)) {
System.out.print("服务端工作目录" + file.getName() + "已存在" + ",");
if (isCoverDirectory) {
if (ftpClient.deleteFile(currentFileName)) {
System.out.print("已删除");
// 在服务端当前目录创建名称为currentFileName的文件夹
if (ftpClient.makeDirectory(currentFileName)) {
System.out.print("已重建");
} else {
System.out.print("重建失败");
}
} else {
System.out.print("删除失败\n");
return false;
}
} else {
System.out.print("保持不变");
}
System.out.print("\n");
} else {
System.out.print("服务端工作目录" + file.getName() + "不存在,");
// 在服务端当前目录创建名称为currentFileName的文件夹
if (ftpClient.makeDirectory(currentFileName)) {
System.out.print("已创建");
} else {
System.out.print("创建失败");
}
System.out.print("\n");
}
String[] fileNames = file.list();
if (fileNames == null || fileNames.length == 0) {
return true;
}
if (ftpClient.changeWorkingDirectory(currentFileName)) {
System.out.println("进入服务端工作目录" + file.getName());
}
for (String fileName : fileNames) {
upload(null, file.getPath() + "/" + fileName, isCoverDirectory, isCoverFile);
}
if (!ftpClient.changeToParentDirectory()) {
System.out.println("返回上一级目录失败");
}
} else {
if (isWorkingDirectoryHasFile(currentFileName)) {
System.out.print("当前服务端工作目录下存在文件:" + file.getName() + ",");
if (isCoverFile) {
FileInputStream fileInputStream = new FileInputStream(file);
// 在服务端当前目录创建名称为currentFileName,文件流为fileInputStream,对应路径filePath的文件
if (ftpClient.storeFile(currentFileName, fileInputStream)) {
System.out.print("已覆盖");
} else {
System.out.print("覆盖失败");
}
fileInputStream.close();
} else {
System.out.print("不覆盖");
}
} else {
System.out.print("当前服务端工作目录下不存在文件:" + file.getName() + ",");
FileInputStream fileInputStream = new FileInputStream(file);
// 在服务端当前目录创建名称为currentFileName,文件流为fileInputStream,对应路径filePath的文件
if (ftpClient.storeFile(currentFileName, fileInputStream)) {
System.out.print("已存储");
} else {
System.out.print("存储失败");
}
fileInputStream.close();
}
System.out.print("\n");
}
return true;
}
/**
* 当前工作目录下是否有查询的文件
*
* @param fileName
* @return
*/
public boolean isWorkingDirectoryHasFile(String fileName) {
try {
FTPFile[] ftpFiles = ftpClient.listFiles();
for (FTPFile ftpFile : ftpFiles) {
if (ftpFile.getName().equals(fileName)) {
return true;
}
}
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
/**
* 得到当前工作目录下的所有文件夹和文件名
*/
public String[] getWorkingDirectoryFileNames() {
try {
FTPFile[] ftpFiles = ftpClient.listFiles();
String[] fileNames = new String[ftpFiles.length];
int i = 0;
for (FTPFile ftpFile : ftpFiles) {
fileNames[i++] = serverCharsetToClient(ftpFile.getName());
}
return fileNames;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* 获得对应服务器路径下的文件,默认使当前服务端目录转移至此文件目录
*
* @param serverPath 服务器路径
*/
public FTPFile getFTPFile(String serverPath) {
String serverFileName = serverPath;
if (serverFileName.indexOf("/") != -1) {
String[] pathItem = serverFileName.split("/");
serverFileName = pathItem[pathItem.length - 1];
}
String serverDirectory = serverCharsetToClient(serverPath.substring(0, serverPath.length() - ("/" + serverFileName).length()));
if (changeWorkingDirectory(serverDirectory)) {
try {
for (FTPFile ftpFile : ftpClient.listFiles()) {
if (ftpFile.getName().equals(serverFileName)) {
return ftpFile;
}
}
} catch (IOException e) {
e.printStackTrace();
}
} else {
System.out.println("服务端工作目录:" + serverDirectory + "不存在");
}
return null;
}
/**
* 下载FTP文件,本地文件已存在则覆盖
*
* @param serverPath 服务器路径
* @param clientPath 本地路径
*/
public boolean downloadFile(String serverPath, String clientPath) {
serverPath = clientCharsetToServer(serverPath);
System.out.println("------------------下载文件--------------------");
File clientDirectory = new File(clientPath);
// 如果文件夹路径不存在,则创建文件夹
if (!clientDirectory.exists()) {
System.out.print("客户端目录:" + clientPath + "不存在,");
if (clientDirectory.mkdirs()) {
System.out.print("已创建");
} else {
System.out.print("创建失败\n");
return false;
}
System.out.print("\n");
}
FTPFile ftpFile = getFTPFile(serverPath);
System.out.println("当前服务端工作目录:" + this.getWorkingDirectory());
if (ftpFile == null) {
System.out.println("服务端工作目录:" + serverCharsetToClient(serverPath) + "不存在");
return false;
}
String clientFilePath = clientPath + "/" + serverCharsetToClient(ftpFile.getName());
File clientFile = new File(clientFilePath);
if (ftpFile.isFile()) {
// 判断文件是否存在,存在则删除重新下载
if (clientFile.exists()) {
System.out.print("文件" + clientFilePath + "已存在,");
if (clientFile.delete()) {
System.out.print("已删除");
} else {
System.out.print("删除失败\n");
return false;
}
System.out.print("\n");
}
try {
OutputStream outputStream = new FileOutputStream(clientFilePath);
// 将服务端当前目录下ftpFile.getName()名称的文件输出到本地路径clientFilePath下
boolean isSuccess = ftpClient.retrieveFile(ftpFile.getName(), outputStream);
outputStream.flush();
outputStream.close();
System.out.println("下载文件:" + clientFilePath + "," + (isSuccess ? "成功" : "失败"));
return isSuccess;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} else {
if (clientFile.exists()) {
System.out.println("文件夹" + clientFilePath + "已存在,");
}else{
if (clientFile.mkdirs()) {
System.out.println("客户端目录:" + clientFilePath + "已建立");
} else {
System.out.println("客户端目录:" + clientFilePath + "建立失败");
return false;
}
}
try {
System.out.println("进入服务端工作目录:" + serverCharsetToClient(ftpFile.getName()));
if (!ftpClient.changeWorkingDirectory(ftpFile.getName())) {
System.out.println(",失败");
return false;
}
} catch (IOException e) {
e.printStackTrace();
}
try {
for (FTPFile ftpFile1 : ftpClient.listFiles()) {
downloadFile(serverCharsetToClient(serverPath + "/" + ftpFile1.getName()), clientFilePath);
}
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
}
}
package ftptest;
/**
* ftp链接常量
*/
public class Ftp {
/**
* ip地址
*/
private String ipAddr;
/**
* 端口号
*/
private Integer port;
/**
* 用户名
*/
private String userName;
/**
* 密码
*/
private String pwd;
public String getIpAddr() {
return ipAddr;
}
public void setIpAddr(String ipAddr) {
this.ipAddr = ipAddr;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}