2 Star 3 Fork 1

Ben / commons

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
FtpClient.java 13.06 KB
AI 代码解读
一键复制 编辑 原始数据 按行查看 历史
Ben 提交于 2023-06-15 13:51 . 规范代码
package com.stark.commons.lang.util;
import lombok.Cleanup;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.*;
import java.io.*;
import java.util.Arrays;
/**
* FTP 客户端。
* @author Ben
* @since 1.0.0
* @version 1.0.0
*/
@SuppressWarnings("unused")
@NoArgsConstructor
public class FtpClient {
private FTPClient ftp;
private String server;
private Integer port;
private String username;
private String password;
private String localCharset = "GBK"; // 如果服务器支持就使用 UTF-8 ,否则使用本地编码,默认 GBK
private static final String SERVER_CHARSET = "ISO-8859-1"; // FTP 协议使用 ISO-8859-1 传输
/**
* 获取 FTP 服务器信息, IP 和端口。
* @return FTP 服务器信息, IP 和端口。
*/
public String getServerInfo() {
return "{"
+ "\"server\":\"" + server + "\","
+ "\"port\":" + port + ","
+ "\"username\":\"" + username + "\","
+ "\"password\":\"" + password + "\""
+ "}";
}
/**
* 连接FTP服务器。
* @param server 服务器地址。
* @param port 端口。
* @param username 用户名。
* @param password 密码。
* @throws IOException 建立连接时抛出异常。
*/
public void connect(String server, int port, String username, String password)
throws IOException {
this.server = server;
this.port = port;
this.username = username;
this.password = password;
boolean flag = false;
try {
ftp = new FTPClient();
ftp.connect(server, port);
int reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
throw new IOException("连接服务器失败: " + getServerInfo() + ", 错误信息: " + reply + "-" + getMsgByCode(reply));
}
if (FTPReply.isPositiveCompletion(ftp.sendCommand("OPTS UTF8", "ON"))) { // 询问服务器是否支持 UTF-8 编码
localCharset = "UTF-8";
}
FTPClientConfig config = new FTPClientConfig();
config.setDefaultDateFormatStr("yyyy-MM-dd HH:mm:ss");
ftp.configure(config);
ftp.setControlEncoding(localCharset);
if (!ftp.login(username, password)) {
throw new IOException("登录失败: " + getServerInfo());
}
ftp.enterLocalPassiveMode();
ftp.setFileType(FTP.BINARY_FILE_TYPE);
flag = true;
} finally {
if (!flag && ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 是否连接中。
* @return 连接中返回 {@literal true} ,否则返回 {@literal false} 。
*/
public boolean isConnected() {
return ftp != null && ftp.isConnected();
}
/**
* 断开FTP服务器。
*/
public void disconnect() {
if (isConnected()) {
try {
ftp.logout();
ftp.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 列举指定路径下所有文件。
* @param dir 相对目录。
* @return 文件名称列表。
*/
public String[] listFiles(String dir) throws IOException {
try {
changeWorkingDirectory(dir);
} catch (Exception e) {
return new String[0];
}
FTPFile[] files = ftp.listFiles();
return Arrays.stream(files)
.filter(FTPFile::isFile)
.map(FTPFile::getName).toArray(String[]::new);
}
/**
* 文件是否存在。
* @param dir 相对目录。
* @param filename 文件名。
* @return 存在返回 {@literal true} ,否则返回 {@literal false} 。
*/
public boolean exists(String dir, String filename) throws IOException {
for (String each : listFiles(dir)) {
if (each.equals(filename)) {
return true;
}
}
return false;
}
/**
* 上传文件。
* @param dir 相对目录。
* @param filename 文件名称,包含后缀。
* @param bytes 文件字节码。
*/
public void uploadFile(String dir, String filename, byte[] bytes) throws IOException {
changeWorkingDirectory("/");
mkdirs(dir);
@Cleanup InputStream in = new ByteArrayInputStream(bytes);
if (!ftp.storeFile(changeEncoding(filename), in)) {
int reply = ftp.getReplyCode();
throw new IOException("上传文件失败: " + getServerInfo()
+ ",dir=" + dir
+ ",filename=" + filename
+ ",errmsg=" + reply + "-" + getMsgByCode(reply));
}
}
/**
* 下载文件。
* @param dir 相对目录。
* @param filename 文件名称。
* @return 文件字节码。
*/
public byte[] downloadFile(String dir, String filename) throws IOException {
changeWorkingDirectory(dir);
@Cleanup ByteArrayOutputStream out = new ByteArrayOutputStream();
if (!ftp.retrieveFile(changeEncoding(filename), out)) {
int reply = ftp.getReplyCode();
throw new IOException("下载文件失败: " + getServerInfo()
+ ",dir=" + dir
+ ",filename=" + filename
+ ",errmsg=" + reply + "-" + getMsgByCode(reply));
}
return out.toByteArray();
}
/**
* 下载文件。
* @param dir 相对目录。
* @param filename 文件名称。
* @param localDir 本地保存路径。
* @param localFilename 本地保存名称。
*/
public void downloadFile(String dir, String filename, String localDir, String localFilename)
throws IOException {
changeWorkingDirectory(dir);
File file = FileUtils.createFile(localDir + File.separator + localFilename);
@Cleanup FileOutputStream out = new FileOutputStream(file);
if (!ftp.retrieveFile(changeEncoding(filename), out)) {
int reply = ftp.getReplyCode();
throw new IOException("下载文件失败: " + getServerInfo()
+ ",dir=" + dir
+ ",filename=" + filename
+ ",errmsg=" + reply + "-" + getMsgByCode(reply));
}
}
/**
* 下载文件。
* @param dir 相对目录。
* @param filename 文件名称。
* @param localDir 本地保存路径。
*/
public void downloadFile(String dir, String filename, String localDir)
throws IOException {
downloadFile(dir, filename, localDir, filename);
}
/**
* 下载文件夹。
* @param dir 相对目录。
* @param localDir 本地存储目录。
*/
public void downloadDirectory(String dir, String localDir) throws IOException {
changeWorkingDirectory(dir);
FileUtils.createDirectory(localDir);
for (FTPFile file : ftp.listFiles()) {
if (file.isDirectory()) {
downloadDirectory(dir + "/" + file.getName(), localDir + "/" + file.getName());
} else {
downloadFile(dir, file.getName(), localDir);
}
}
}
/**
* 创建目录。
* @param dir 相对目录。
*/
public void mkdirs(String dir) throws IOException {
String[] dirArray = formatPath(dir).split("/");
for (String dirItem : dirArray) {
if (StringUtils.isNotBlank(dirItem)) {
dirItem = changeEncoding(dirItem);
if (!ftp.changeWorkingDirectory(dirItem)) {
if (!ftp.makeDirectory(dirItem)
|| !ftp.changeWorkingDirectory(dirItem)) {
int reply = ftp.getReplyCode();
throw new IOException("创建目录失败: " + getServerInfo()
+ ",dir=" + dir
+ ",errmsg=" + reply + "-" + getMsgByCode(reply));
}
}
}
}
}
/**
* 删除文件。
* @param dir 相对目录。
* @param filename 文件名称(包含后缀)。
*/
public void deleteFile(String dir, String filename) throws IOException {
try {
changeWorkingDirectory(dir);
} catch (Exception e) {
return;
}
if (!ftp.deleteFile(changeEncoding(filename))) {
int reply = ftp.getReplyCode();
throw new IOException("删除文件失败: " + getServerInfo()
+ ",dir=" + dir
+ ",filename=" + filename
+ ",errmsg=" + reply + "-" + getMsgByCode(reply));
}
}
/**
* 重命名文件夹或文件。
* @param dir 相对目录。
* @param sourceName 原文件夹名或文件名。
* @param destName 新文件夹名或文件名。
*/
public void rename(String dir, String sourceName, String destName) throws IOException {
if (!ftp.rename(changeEncoding(dir + "/" + sourceName), changeEncoding(dir + "/" + destName))) {
int reply = ftp.getReplyCode();
throw new IOException("重命名失败: " + getServerInfo()
+ ",dir=" + dir
+ ",sourceName=" + sourceName
+ ",destName=" + destName
+ ",errmsg=" + reply + "-" + getMsgByCode(reply));
}
}
/**
* 切换工作目录。
* @param dir 相对目录。
*/
private void changeWorkingDirectory(String dir) throws IOException {
if (!ftp.changeWorkingDirectory(changeEncoding(formatPath(dir)))) {
String _localCharset = localCharset;
if ("UTF-8".equals(_localCharset)) {
localCharset = "GBK";
} else {
localCharset = "UTF-8";
}
if (!ftp.changeWorkingDirectory(changeEncoding(formatPath(dir)))) {
localCharset = _localCharset;
int reply = ftp.getReplyCode();
throw new IOException("切换目录失败: " + getServerInfo()
+ ",dir=" + dir
+ ",errmsg=" + reply + "-" + getMsgByCode(reply));
}
}
}
/**
* 格式化路径,兼容各个系统。
* @param path 路径。
* @return 格式化后的路径。
*/
private String formatPath(String path) {
path = path.replace("\\", "/");
return path;
}
/**
* 字符串转码。
* @param str 字符串。
* @return 转码后的字符串。
*/
private String changeEncoding(String str) throws UnsupportedEncodingException {
str = new String(str.getBytes(localCharset), SERVER_CHARSET);
return str;
}
private String getMsgByCode(int code) {
switch (code) {
case FTPReply.RESTART_MARKER:
return "重新启动标记应答";
case FTPReply.SERVICE_NOT_READY:
return "服务不可用";
case FTPReply.DATA_CONNECTION_ALREADY_OPEN:
return "数据连接已经打开,开始传送数据";
case FTPReply.FILE_STATUS_OK:
return "文件状态正确,正在打开数据连接";
case FTPReply.COMMAND_OK:
return "命令执行正常结束";
case FTPReply.COMMAND_IS_SUPERFLUOUS:
return "命令未被执行,此站点不支持此命令";
case FTPReply.SYSTEM_STATUS:
return "系统状态或系统帮助信息回应";
case FTPReply.DIRECTORY_STATUS:
return "目录状态信息";
case FTPReply.FILE_STATUS:
return "文件状态信息";
case FTPReply.HELP_MESSAGE:
return "帮助信息";
case FTPReply.NAME_SYSTEM_TYPE:
return "NAME系统类型";
case FTPReply.SERVICE_READY:
return "服务已就绪";
case FTPReply.SERVICE_CLOSING_CONTROL_CONNECTION:
return "控制连接关闭";
case FTPReply.DATA_CONNECTION_OPEN:
return "数据连接已打开,没有进行中的数据传送";
case FTPReply.CLOSING_DATA_CONNECTION:
return "正在关闭数据连接。请求文件动作成功结束";
case FTPReply.ENTERING_PASSIVE_MODE:
return "进入被动模式";
case FTPReply.ENTERING_EPSV_MODE:
return "进入EPSV模式";
case FTPReply.USER_LOGGED_IN:
return "用户登入";
case FTPReply.FILE_ACTION_OK:
return "文件操作成功";
case FTPReply.PATHNAME_CREATED:
return "路径已创建";
case FTPReply.NEED_PASSWORD:
return "请输入密码";
case FTPReply.NEED_ACCOUNT:
return "请输入用户名";
case FTPReply.FILE_ACTION_PENDING:
return "文件操作需要更多信息";
case FTPReply.SERVICE_NOT_AVAILABLE:
return "服务不可用";
case FTPReply.CANNOT_OPEN_DATA_CONNECTION:
return "无法打开数据连接";
case FTPReply.TRANSFER_ABORTED:
return "传输中止";
case FTPReply.FILE_ACTION_NOT_TAKEN:
return "文件操作请求未执行";
case FTPReply.ACTION_ABORTED:
return "操作中止,处理过程中发生本地错误";
case FTPReply.INSUFFICIENT_STORAGE:
return "存储空间不足";
case FTPReply.UNRECOGNIZED_COMMAND:
return "无法识别的命令";
case FTPReply.SYNTAX_ERROR_IN_ARGUMENTS:
return "参数语法错误";
case FTPReply.COMMAND_NOT_IMPLEMENTED:
return "命令未执行";
case FTPReply.BAD_COMMAND_SEQUENCE:
return "命令次序错误";
case FTPReply.COMMAND_NOT_IMPLEMENTED_FOR_PARAMETER:
return "由于参数错误导致命令未执行";
case FTPReply.NOT_LOGGED_IN:
return "未登录";
case FTPReply.NEED_ACCOUNT_FOR_STORING_FILES:
return "存储文件需要用户信息";
case FTPReply.FILE_UNAVAILABLE:
return "文件无权访问";
case FTPReply.PAGE_TYPE_UNKNOWN:
return "页面类型未知";
case FTPReply.STORAGE_ALLOCATION_EXCEEDED:
return "存储空间分配超出";
case FTPReply.FILE_NAME_NOT_ALLOWED:
return "文件名非法";
case FTPReply.SECURITY_DATA_EXCHANGE_COMPLETE:
return "安全数据交换完成";
case FTPReply.SECURITY_DATA_EXCHANGE_SUCCESSFULLY:
return "安全数据交换成功";
case FTPReply.SECURITY_MECHANISM_IS_OK:
return "安全策略正常";
case FTPReply.SECURITY_DATA_IS_ACCEPTABLE:
return "安全数据读取正常";
case FTPReply.UNAVAILABLE_RESOURCE:
return "资源不可用";
case FTPReply.BAD_TLS_NEGOTIATION_OR_DATA_ENCRYPTION_REQUIRED:
return "TLS协商失败或者数据需要加密";
case FTPReply.DENIED_FOR_POLICY_REASONS:
return "由于协议原因被拒绝访问";
case FTPReply.REQUEST_DENIED:
return "请求被拒绝";
case FTPReply.FAILED_SECURITY_CHECK:
return "安全检查失败";
case FTPReply.REQUESTED_PROT_LEVEL_NOT_SUPPORTED:
return "请求再端口级别不被支持";
}
return "";
}
}
Java
1
https://gitee.com/jarvis-lib/commons.git
git@gitee.com:jarvis-lib/commons.git
jarvis-lib
commons
commons
master

搜索帮助