FTP工具类

工具类:

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;
import java.util.List;
import java.util.Objects;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

/**
 * FTP工具类
 * @author zql
 * @createTime 2020-12-01 21:10:38
 * @version 1.1
 * @modifyLog 1.1 优化代码
 *
 */
public class FtpUtil {
	
	/**
	 * FTP主机服务器
	 */
	private static String FTP_HOST = "192.168.1.101";
	/**
	 * FTP登录用户名
	 */
	private static String FTP_USER_NAME = "ftpservice";
	/**
	 * FTP 登录密码
	 */
	private static String FTP_PASSWORD = "ftp_service";
	/**
	 * FTP端口
	 */
	private static int FTP_PORT = 2121;
    /**
     * 本地字符编码
     */
    private static String LOCAL_CHARSET = "GBK";
    /**
     * ftp服务器对象
     */
    private static FTPClient ftpClient = null;

    /**
     * 开启FTP服务器连接
     * @author zql
     * @createTime 2020-12-01 21:41:49
     *
     */
    public static void openConnect() {
		try {
			FtpUtil.ftpClient = new FTPClient();
			// 连接FTP服务器
			FtpUtil.ftpClient.connect(FtpUtil.FTP_HOST, FtpUtil.FTP_PORT);
			// 登陆FTP服务器
			FtpUtil.ftpClient.login(FtpUtil.FTP_USER_NAME, FtpUtil.FTP_PASSWORD);
			if (!FTPReply.isPositiveCompletion(FtpUtil.ftpClient.getReplyCode())) {
				System.out.println("未连接到FTP,用户名或密码错误");
				FtpUtil.ftpClient.disconnect();
			} else {
				System.out.println("FTP连接成功");
			}
		} catch (SocketException e) {
			e.printStackTrace();
			System.out.println("FTP的IP地址可能错误,请正确配置");
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("FTP的端口错误,请正确配置");
		}
    }
    
    /**
     * 关闭FTP服务器连接
     * @author zql
     * @createTime 2020-12-01 21:41:27
     *
     */
    public static void closeConnect() {
		if (FtpUtil.ftpClient.isConnected()) {
			try {
				FtpUtil.ftpClient.disconnect();
				System.out.println("FTP关闭成功");
			} catch (IOException ioe) {
				System.out.println("FTP关闭失败");
			}
		}
    }
    
    /**
     * 判断是否开启FTP连接,如果FTPClient对象为NULL或未开启则抛出异常
     * @author zql
     * @createTime 2020-12-01 21:41:17
     *
     * @throws Exception
     */
    public static void isOpenConnect() throws Exception {
		if (Objects.isNull(FtpUtil.ftpClient) || !FtpUtil.ftpClient.isConnected()) {
			throw new Exception("FTP连接未开启");
		}
    }
    
    /**
     * 切换FTP路径
     * @author zql
     * @createTime 2020-12-01 21:41:03
     *
     * @param path
     * @throws Exception
     */
    public static void changeWorkingDirectory(String path) throws Exception {
    	boolean bl = FtpUtil.ftpClient.changeWorkingDirectory(path);
    	if (!bl) {
    		throw new Exception("未找到该路径:" + path);
    	}
    }
    
	/**
	 * 从FTP服务器下载文件
	 * @author zql
	 * @createTime 2020-12-01 21:40:45
	 *
	 * @param ftpPath FTP服务器文件路径,格式:/root/test
	 * @param localPath 本地保存文件的路径,格式:E:/test
	 * @param fileName FTP服务器文件名,格式:text.txt
	 */
	public static void downloadFtpFile(String ftpPath, String localPath, String fileName) {
		try {
			FtpUtil.isOpenConnect();
			// 中文支持
			FtpUtil.ftpClient.setControlEncoding("UTF-8");
			FtpUtil.ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
			/*
			 * 这里修改为被动模式 主动模式:客户端开放端口给服务端用; 被动模式:服务端开放端口给客户端用。
			 * 由于很多客户端在防火墙内,开放端口给服务器端用比较困难。所以用被动模式的时候比较多。
			 */
			FtpUtil.ftpClient.enterLocalPassiveMode();
			FtpUtil.ftpClient.changeWorkingDirectory(ftpPath);

			File localFile = new File(localPath + File.separatorChar + fileName);
			OutputStream os = new FileOutputStream(localFile);
			FtpUtil.ftpClient.retrieveFile(fileName, os);
			os.close();
			FtpUtil.ftpClient.logout();
		} catch (FileNotFoundException e) {
			System.out.println("没有找到" + ftpPath + "文件");
			e.printStackTrace();
		} catch (SocketException e) {
			System.out.println("连接FTP失败");
			e.printStackTrace();
		} catch (IOException e) {
			System.out.println("文件读取错误");
			e.printStackTrace();
		} catch (Exception e) {
			System.out.println("FTP连接未开启");
			e.printStackTrace();
		}
	}

	/**
	 * 向FTP服务器上传文件
	 * @author zql
	 * @createTime 2020-12-01 21:40:21
	 *
	 * @param ftpPath FTP服务器中文件所在路径 格式: /root/test或root/test/
	 * @param fileName ftp文件名称
	 * @param input 文件流
	 * @return 成功返回true,否则返回false
	 */
	public static boolean uploadFile(String ftpPath, String fileName, InputStream input) {
		boolean success = false;
		try {
			FtpUtil.isOpenConnect();
			int reply = FtpUtil.ftpClient.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply)) {
				FtpUtil.ftpClient.disconnect();
				return success;
			}
			// 查看服务器的编码格式是UTF-8还是GBK
			// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码,否则就使用本地编码(GBK).
			if (FTPReply.isPositiveCompletion(FtpUtil.ftpClient.sendCommand("OPTS UTF8", "ON"))) {
				FtpUtil.LOCAL_CHARSET = "UTF-8";
			}
			// 中文支持
			FtpUtil.ftpClient.setControlEncoding(FtpUtil.LOCAL_CHARSET);
			// ftp上传文件是以文本形式传输的,所以多媒体文件会失真,需要转为二进制形式传输
			FtpUtil.ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
			/*
			 * 这里修改为被动模式 主动模式:客户端开放端口给服务端用; 被动模式:服务端开放端口给客户端用。
			 * 由于很多客户端在防火墙内,开放端口给服务器端用比较困难。所以用被动模式的时候比较多。
			 */
			FtpUtil.ftpClient.enterLocalPassiveMode();

			FtpUtil.createDirectory(FtpUtil.ftpClient, ftpPath);

			FtpUtil.ftpClient.storeFile(fileName, input);

			input.close();
			FtpUtil.ftpClient.logout();
			success = true;
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("FTP服务器上传文件失败:" + e.getMessage());
		} catch (Exception e) {
			System.out.println("FTP连接未开启");
			e.printStackTrace();
		} finally {
			FtpUtil.closeConnect();
		}
		return success;
	}

	/**
     * 删除ftp上的文件
     * @author zql
     * @createTime 2020-12-01 21:39:46
     *
     * @param filePath 文件路径(后边需要跟上文件名)
     * @return
     * @throws Exception
     */
    public static boolean deleteFtpFile(String filePath) throws Exception {
    	FtpUtil.isOpenConnect();
		// 修改为被动模式
		FtpUtil.ftpClient.enterLocalPassiveMode();
		// 删除文件
		return FtpUtil.ftpClient.deleteFile(filePath);
    }
    
    /**
     * 删除ftp上指定目录的所有文件
     * @author zql
     * @createTime 2020-12-01 21:32:01
     *
     * @param path 指定目录,格式:/root/test/
     * @param isDelDirectory 是否删除指定目录,true删除,false不删除
     * @return
     * @throws Exception
     */
    public static boolean deleteAllFtpFile(String path,boolean isDelDirectory) throws Exception {
    	FtpUtil.isOpenConnect();
		boolean bl = false;
		// 修改为被动模式
		FtpUtil.ftpClient.enterLocalPassiveMode();
		// 更换目录到当前目录
		FtpUtil.changeWorkingDirectory(path);
		FTPFile[] files = FtpUtil.ftpClient.listFiles();
		// 删除所有文件
		for (FTPFile file : files) {
			if (file.isFile()) {
				bl = FtpUtil.ftpClient.deleteFile(path + file.getName());
			} else if (file.isDirectory() && FtpUtil.isContext(file.getName())) {
				bl = FtpUtil.deleteAllFtpFile(path + file.getName() + "/", true);
			}
			// 如果删除失败直接结束返回
			if (!bl) {
				return bl;
			}
		}
		if (isDelDirectory) {
			// 更换目录到当前目录
			FtpUtil.changeWorkingDirectory(path);
			FTPFile[] list = FtpUtil.ftpClient.listFiles();
			// 目录下没有文件
			if (list.length == 0) {
				// 删除目录
				bl = FtpUtil.ftpClient.deleteFile(path);
			}
		}
		return bl;
    }
	
    /**
     * 下载/浏览器预览需要的流信息
     * @author zql
     * @createTime 2020-12-01 21:31:26
     *
     * @param filePath
     * @return
     * @throws Exception
     */
    public static InputStream getFtpFileStream(String filePath) throws Exception {
    	FtpUtil.isOpenConnect();
		InputStream inputStream = FtpUtil.ftpClient.retrieveFileStream(filePath);
		return inputStream;
    }
    
    /**
     * 判断ftp服务器文件是否存在    
     * @author zql
     * @createTime 2020-12-01 21:31:11
     *
     * @param path
     * @return
     * @throws Exception
     */
    public static boolean existFile(String path) throws Exception {
    	FtpUtil.isOpenConnect();
		boolean flag = false;
		/*
		 * 如果传入的path是目录(格式root/test),FTPFile得到的就是该目录下的子目录及文件列表,
		 * 如果传入的path是文件(格式root/test/test.txt),FTPFile得到的就是该文件。
		 */
		FTPFile[] ftpFileArr = FtpUtil.ftpClient.listFiles(path);
		if (ftpFileArr.length > 0) {
			flag = true;
		}
		return flag;
	}
    
    /**
     * 获得ftp服务器文件的最后修改时间,返回格式:YYYYMMDDhhmmss
     * @author zql
     * @createTime 2020-12-01 21:30:51
     *
     * @param path
     * @return
     * @throws Exception
     */
    public static String getModificationTime(String path) throws Exception {
    	FtpUtil.isOpenConnect();
    	return FtpUtil.ftpClient.getModificationTime(path);
    }
	
	
    /**
     * 递归遍历出FTP目录下面所有文件
     * @author zql
     * @createTime 2020-12-01 21:26:10
     *
     * @param pathName 需要遍历的目录,必须以"/"开始和结束
     * @param filePathList 用于保存文件路径的列表
     * @throws Exception
     */
    public static void FTPFilePathList(String pathName, List<String> filePathList) throws Exception {
    	FtpUtil.FTPFilePathList(pathName, filePathList, null);
    }
    
    /**
     * 递归遍历目录下面指定的文件名
     * @author zql
     * @createTime 2020-12-01 21:15:57
     *
     * @param pathName 需要遍历的目录,必须以"/"开始和结束
     * @param filePathList 用于保存文件路径的列表
     * @param suffix 文件的扩展名,例如:txt
     * @throws Exception
     */
    public static void FTPFilePathList(String pathName, List<String> filePathList, String suffix) throws Exception {
		FtpUtil.isOpenConnect();
		String with = "/";
		if (pathName.startsWith(with) && pathName.endsWith(with)) {
			// 更换目录到当前目录
			FtpUtil.ftpClient.changeWorkingDirectory(pathName);
			FTPFile[] files = FtpUtil.ftpClient.listFiles();
			boolean flag = true;
			for (FTPFile file : files) {
				if (Objects.nonNull(suffix)) {
					flag = file.getName().endsWith(suffix);
				}
				if (file.isFile() && flag) {
					filePathList.add(pathName + file.getName());
				} else if (file.isDirectory() && FtpUtil.isContext(file.getName())) {
					FtpUtil.FTPFilePathList(pathName + file.getName() + "/", filePathList, suffix);
				}
			}
		}
    }
    
    /**
	 * 新建FTP目录并切换当前的工作目录为新建的目录
	 * @author zql
	 * @createTime 2020-12-01 21:28:11
	 *
	 * @param ftpClient
	 * @param path FTP服务器中文件所在路径 格式: root/test或root/test/
	 */
	private static void createDirectory(FTPClient ftpClient, String path) {
		try {
			String with = "/";
			// 切换工作目录为根目录
			ftpClient.changeWorkingDirectory(with);

			// 如果输入的路径不为空或者不为根路径,则转换操作目录
			if (!(Objects.isNull(path) || path.length() == 0 || with.equals(path))) {
				// 循环创建多级目录
				String directory = path.endsWith(with) ? path : path + with;
				// 目录不存在
				boolean isExistDirectory = !ftpClient.changeWorkingDirectory(new String(directory.getBytes("GBK"), "iso-8859-1"));
				// 非根目录
				boolean isRoot = !with.equalsIgnoreCase(directory);
				// 如果远程目录不存在,则递归创建远程服务器目录
				if (isRoot && isExistDirectory) {
					// 检测字符串是否以“/”的前缀开始
					int start = directory.startsWith(with) ? 1 : 0;
					// 返回从 start
					// 位置开始查找“/”字符在字符串directory中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。
					int end = directory.indexOf(with, start);
					while (end > start) {
						String subDirectory = new String(path.substring(start, end).getBytes("GBK"), "iso-8859-1");
						// 不存在子目录
						if (!ftpClient.changeWorkingDirectory(subDirectory)) {
							// makeDirectory函数只能创建一级目录,不能创建多级目录
							if (ftpClient.makeDirectory(subDirectory)) {
								// 切换到创建的子目录
								ftpClient.changeWorkingDirectory(subDirectory);
							} else {
								System.out.println("创建目录失败");
							}
						}
						start = end + 1;
						end = directory.indexOf(with, start);
					}
				}
				// 切换当前的工作目录为新建的目录
				FtpUtil.changeWorkingDirectory(path);
			}
		} catch (Exception e) {
			System.out.println("FTP上传文件进行创建目录结构的时候出现了异常:" + e.getMessage());
		}
    }
	
	/**
	 * 递归需要加此判断。否则,ftp默认将‘项目文件所在目录之下的目录(./)’与‘项目文件所在目录向上一级目录下的目录(../)’都纳入递归,这样下去就陷入一个死循环了。需将其过滤掉。
	 * @author zql
	 * @createTime 2020-12-01 21:34:59
	 *
	 * @param fileName
	 * @return
	 */
	private static boolean isContext(String fileName) {
		return !".".equals(fileName) && !"..".equals(fileName);
	}

}


测试类:

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;

/**
 * FTP工具测试类
 *
 * @author zql
 * @version 1.0
 * @createTime 2021-01-02 15:16:00
 * @modifyLog
 */
public class FtpUtilTest {

    @Before
    public void openConnect() {
        FtpUtil.openConnect();
    }

    @After
    public void closeConnect() {
        FtpUtil.closeConnect();
    }

    /**
     * 下载文件测试
     */
    @Test
    public void downloadFtpFile() {
        String ftpPath = "/root/test/";
        String localPath = "E:/test";
        String fileName = "test2.txt";
        FtpUtil.downloadFtpFile(ftpPath, localPath, fileName);
    }

    /**
     * 上传文件测试
     *
     * @throws Exception
     */
    @Test
    public void uploadFile() throws FileNotFoundException {
        String ftpPath = "/root/test/";
        String localPath = "E:/test/test.txt";
        String fileName = "test1.txt";
        // 上传一个文件
        FileInputStream in = new FileInputStream(new File(localPath));
        boolean isUpload = FtpUtil.uploadFile(ftpPath, fileName, in);
        if (isUpload) {
            System.out.println("文件上传成功。");
        } else {
            System.out.println("文件上传失败。");
        }
    }

    /**
     * 删除文件测试
     *
     * @throws Exception
     */
    @Test
    public void deleteFtpFile() throws Exception {
        boolean bl = FtpUtil.deleteFtpFile("/root/test/test1.txt");
        if (bl) {
            System.out.println("成功删除文件");
        } else {
            System.out.println("删除文件失败");
        }
    }

    /**
     * 删除所有文件测试
     *
     * @throws Exception
     */
    @Test
    public void deleteAllFtpFile() throws Exception {
        boolean bl = FtpUtil.deleteAllFtpFile("/root/test/", true);
        FtpUtil.closeConnect();
        if (bl) {
            System.out.println("成功删除所有文件");
        } else {
            System.out.println("删除所有文件失败");
        }
    }

    /**
     * 获取所有文件路径测试
     *
     * @throws Exception
     */
    @Test
    public void FTPFilePathList() throws Exception {
        String ftpPath = "/root/";
        List<String> filePath = new ArrayList<String>();
        FtpUtil.FTPFilePathList(ftpPath, filePath);
        for (String s : filePath) {
            System.out.println(s);
        }
    }

    /**
     * 获取指定文件路径测试
     *
     * @throws Exception
     */
    @Test
    public void getSpecifiFilePath() throws Exception {
        String ftpPath = "/root/";
        List<String> filePath = new ArrayList<String>();
        FtpUtil.FTPFilePathList(ftpPath, filePath, "txt");
        for (String s : filePath) {
            System.out.println(s);
        }
    }
}

普通项目需要引入的包
commons-net-3.6.jar

maven项目依赖

<!-- FTP maven依赖 -->
<!-- https://mvnrepository.com/artifact/commons-net/commons-net -->
<dependency>
  <groupId>commons-net</groupId>
  <artifactId>commons-net</artifactId>
  <version>3.6</version>
</dependency>
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个Java的FTP工具类的示例代码: ```java import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPReply; import java.io.*; public class FTPUtil { private FTPClient ftpClient; public FTPUtil() { ftpClient = new FTPClient(); } public boolean connect(String server, int port, String user, String password) { try { ftpClient.connect(server, port); int replyCode = ftpClient.getReplyCode(); if (!FTPReply.isPositiveCompletion(replyCode)) { return false; } boolean success = ftpClient.login(user, password); if (!success) { return false; } ftpClient.setFileType(FTP.BINARY_FILE_TYPE); ftpClient.enterLocalPassiveMode(); return true; } catch (IOException e) { e.printStackTrace(); return false; } } public boolean uploadFile(String localFilePath, String remoteFilePath) { try (InputStream inputStream = new FileInputStream(localFilePath)) { return ftpClient.storeFile(remoteFilePath, inputStream); } catch (IOException e) { e.printStackTrace(); return false; } } public boolean downloadFile(String remoteFilePath, String localFilePath) { try (OutputStream outputStream = new FileOutputStream(localFilePath)) { return ftpClient.retrieveFile(remoteFilePath, outputStream); } catch (IOException e) { e.printStackTrace(); return false; } } public boolean disconnect() { try { ftpClient.logout(); ftpClient.disconnect(); return true; } catch (IOException e) { e.printStackTrace(); return false; } } } ``` 使用该工具类,你可以连接到FTP服务器,上传文件和下载文件。你需要引入Apache Commons Net库,该库提供了FTP客户端的实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值