本地Windows开发环境下,FTP传输文件正常,但将服务部署到Linux环境时,会出现无响应的状态。
1 在FTP服务中,涉及到客户端和服务器端的连接,连接就会涉及到端口的打开问题;
2 而端口的打开中,又涉及到主动模式和被动模式。主动模式:客户端开放端口给服务端用;被动模式:服务端开放端口给客户端用。
由于很多客户端在防火墙内,开放端口给服务器端用比较困难。所以用被动模式的时候比较多。
所以在storeFile(),listFiles()时之前需要调用 ftpClient.enterLocalPassiveMode();
这个方法的意思就是每次数据连接之前,ftpClient告诉ftp server开通一个端口来传输数据。
FTP传输文件
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.net.MalformedURLException;
@Slf4j
public class FTPUtil {
//ftp服务器地址
private static String HOST_NAME = PropertiesUtil.getProperty("ftp.server.ip");
//ftp服务器端口号默认为21
private static Integer PORT = Integer.valueOf(PropertiesUtil.getProperty("ftp.port"));
//ftp登录账号
private static String USERNAME = PropertiesUtil.getProperty("ftp.user");
//ftp登录密码
private static String PASSWORD = PropertiesUtil.getProperty("ftp.pass");
private static FTPClient ftpClient = null;
/**
* 初始化ftp服务器
*/
private static void initFtpClient() {
ftpClient = new FTPClient();
ftpClient.setControlEncoding("utf-8");
try {
log.info("connecting...ftp服务器:" + HOST_NAME + ":" + PORT);
//连接ftp服务器
ftpClient.connect(HOST_NAME, PORT);
//登录ftp服务器
ftpClient.login(USERNAME, PASSWORD);
ftpClient.sendCommand("OPTS UTF8", "ON");
//是否成功登录服务器
int replyCode = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(replyCode)) {
log.info("connect failed...ftp服务器:" + HOST_NAME + ":" + PORT);
} else {
log.info("connect successful...ftp服务器:" + HOST_NAME + ":" + PORT);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 上传文件
*
* @param pathname ftp服务保存地址
* @param fileName 上传到ftp的文件名
* @param originfilename 待上传文件的名称(绝对地址) *
* @return
*/
public static boolean uploadFile(String pathname, String fileName, String originfilename) {
boolean flag = false;
InputStream inputStream = null;
try {
log.info("开始上传文件");
inputStream = new FileInputStream(new File(originfilename));
initFtpClient();
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
CreateDirecroty(pathname);
ftpClient.makeDirectory(pathname);
ftpClient.changeWorkingDirectory(pathname);
ftpClient.enterLocalPassiveMode();
ftpClient.storeFile(fileName, inputStream);
inputStream.close();
ftpClient.logout();
flag = true;
log.info("上传文件成功");
} catch (Exception e) {
log.info("上传文件失败");
e.printStackTrace();
} finally {
if (ftpClient.isConnected()) {
try {
ftpClient.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != inputStream) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
}
/**
* 上传文件
* @param pathname ftp服务保存地址
* @param file 文件
* @param fileName 上传到ftp的文件名
* @return
*/
public static boolean uploadFile(String pathname, MultipartFile file, String fileName) {
boolean flag = false;
try {
initFtpClient();
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
CreateDirecroty(pathname);
ftpClient.makeDirectory(pathname);
ftpClient.changeWorkingDirectory(pathname);
ftpClient.enterLocalPassiveMode();
ftpClient.storeFile(fileName, file.getInputStream());
ftpClient.logout();
flag = true;
log.info("上传文件成功");
} catch (Exception e) {
log.info("上传文件失败");
e.printStackTrace();
} finally {
if (ftpClient.isConnected()) {
try {
ftpClient.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return flag;
}
/**
* 下载文件
*
* @param pathName
* @param filename
* @param out
* @return
*/
public static boolean downloadFile(String pathName, String filename, OutputStream out) {
try {
log.info("开始下载文件");
initFtpClient();
//切换FTP目录
ftpClient.changeWorkingDirectory(pathName);
ftpClient.enterLocalPassiveMode();
FTPFile[] ftpFiles = ftpClient.listFiles();
for (FTPFile file : ftpFiles) {
if (filename.equalsIgnoreCase(file.getName())) {
InputStream inputStream = ftpClient.retrieveFileStream(filename);
byte[] buffer = new byte[1024 * 4];
int n = 0;
while ((n = inputStream.read(buffer)) != -1) {
out.write(buffer, 0, n);
}
out.flush();
}
}
ftpClient.logout();
log.info("下载文件成功");
return true;
} catch (Exception e) {
log.info("下载文件失败");
e.printStackTrace();
return false;
} finally {
try {
out.close();
if (ftpClient.isConnected()) {
ftpClient.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 删除文件 *
*
* @param pathname FTP服务器保存目录 *
* @param filename 要删除的文件名称 *
* @return
*/
public static boolean deleteFile(String pathname, String filename) {
boolean flag = false;
try {
log.info("开始删除文件");
initFtpClient();
//切换FTP目录
ftpClient.changeWorkingDirectory(pathname);
ftpClient.dele(filename);
ftpClient.logout();
flag = true;
log.info("删除文件成功");
} catch (Exception e) {
log.info("删除文件失败");
e.printStackTrace();
} finally {
if (ftpClient.isConnected()) {
try {
ftpClient.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return flag;
}
/**
* 改变目录路径
*/
public static boolean changeWorkingDirectory(String directory) {
boolean flag = true;
try {
flag = ftpClient.changeWorkingDirectory(directory);
if (flag) {
log.info("进入文件夹" + directory + " 成功!");
} else {
log.info("进入文件夹" + directory + " 失败!开始创建文件夹");
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
return flag;
}
/**
* 创建多层目录文件,如果有ftp服务器已存在该文件,则不创建,如果无,则创建
*
* @param remote
* @return
* @throws IOException
*/
public static boolean CreateDirecroty(String remote) throws IOException {
boolean success = true;
String directory = remote + "/";
// 如果远程目录不存在,则递归创建远程服务器目录
if (!directory.equalsIgnoreCase("/") && !changeWorkingDirectory(new String(directory))) {
int start = 0;
int end = 0;
if (directory.startsWith("/")) {
start = 1;
} else {
start = 0;
}
end = directory.indexOf("/", start);
String path = "";
String paths = "";
while (true) {
String subDirectory = remote.substring(start, end);
path = path + "/" + subDirectory;
if (!existFile(path)) {
if (makeDirectory(subDirectory)) {
changeWorkingDirectory(subDirectory);
} else {
log.info("创建目录[" + subDirectory + "]失败");
changeWorkingDirectory(subDirectory);
}
} else {
changeWorkingDirectory(subDirectory);
}
paths = paths + "/" + subDirectory;
start = end + 1;
end = directory.indexOf("/", start);
// 检查所有目录是否创建完毕
if (end <= start) {
break;
}
}
}
return success;
}
/**
* 判断ftp服务器文件是否存在
*
* @param path
* @return
* @throws IOException
*/
public static boolean existFile(String path) throws IOException {
boolean flag = false;
FTPFile[] ftpFileArr = ftpClient.listFiles(path);
if (ftpFileArr.length > 0) {
flag = true;
}
return flag;
}
/**
* 创建目录
*/
public static boolean makeDirectory(String dir) {
boolean flag = true;
try {
flag = ftpClient.makeDirectory(dir);
if (flag) {
log.info("创建文件夹" + dir + " 成功!");
} else {
log.info("创建文件夹" + dir + " 失败!");
}
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}
}
此外,保持连接的同时,需要对多个FTP文件进行操作,一定要调用completePendingCommand()释放,否则FTP会断开连接
//操作多文件时候,必须调用completePendingCommand释放,否则FTP会断开连接
ftpClient.completePendingCommand();