java實現連線vsftpd伺服器,上傳,下載,刪除。
核心程式碼如下:
package com.bh.service;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.bh.common.ExceptionUtil;
/**
* FTP服務工具類
*
* @author: Rodge @time: 2017年12月24日 下午23:02:37 @version: V1.0.0
*/
@Component
public class FTPUtilService {
/** 日誌物件 **/
private static final Logger log = LoggerFactory.getLogger(FTPUtilService.class);
/** FTP地址 **/
@Value(value = "${ftp.ftp_address}")
private String ftp_address;
/** FTP埠 **/
@Value(value = "${ftp.ftp_port}")
private String ftp_port;
/** FTP使用者名稱 **/
@Value(value = "${ftp.ftp_username}")
private String ftp_username;
/** FTP密碼 **/
@Value(value = "${ftp.ftp_password}")
private String ftp_password;
/** FTP基礎目錄 **/
private static final String base_path = "";
/** 本地字元編碼 **/
@Value(value = "${ftp.localCharset}")
private String localCharset;
/** FTP協議裡面,規定檔名編碼為iso-8859-1 **/
@Value(value = "${ftp.serverCharset}")
private String serverCharset;
/** UTF-8字元編碼 **/
private static final String CHARSET_UTF8 = "UTF-8";
/** OPTS UTF8字串常量 **/
private static final String OPTS_UTF8 = "OPTS UTF8";
/** 設定緩衝區大小40M **/
@Value(value = "${ftp.buffer_size}")
private String buffer_size;
/** FTPClient物件 **/
private static FTPClient ftpClient = null;
/**
* 本地檔案上傳到FTP伺服器
*
* @param ftpPath
* FTP伺服器檔案相對路徑,例如:test/123
* @param multipartFileIOS
* 上傳時前臺傳過來的multipartFile的檔案輸入流
* @param fileName
* 上傳到FTP服務的檔名,例如:666.txt
* @return boolean 成功返回true,否則返回false
*/
public boolean uploadLocalFile(String ftpPath, InputStream multipartFileIOS, String fileName) {
// 登入
login(ftp_address, Integer.parseInt(ftp_port), ftp_username, ftp_password);
boolean flag = false;
if (ftpClient != null) {
InputStream fis = null;
try {
fis = multipartFileIOS;
ftpClient.setBufferSize(Integer.parseInt(buffer_size));
// 設定編碼:開啟伺服器對UTF-8的支援,如果伺服器支援就用UTF-8編碼,否則就使用本地編碼(GBK)
if (FTPReply.isPositiveCompletion(ftpClient.sendCommand(OPTS_UTF8, "ON"))) {
localCharset = CHARSET_UTF8;
}
ftpClient.setControlEncoding(localCharset);
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
if (!base_path.isEmpty() || !ftpPath.isEmpty()) {
String path = changeEncoding(base_path + ftpPath);
// 目錄不存在,則遞迴建立
if (!ftpClient.changeWorkingDirectory(path)) {
this.createDirectorys(path);
}
}
// 設定被動模式,開通一個埠來傳輸資料
ftpClient.enterLocalPassiveMode();
// 上傳檔案
flag = ftpClient.storeFile(new String(fileName.getBytes(localCharset), serverCharset), fis);
if (flag) {
System.out.println("檔案上傳成功");
} else {
System.out.println("檔案上傳失敗");
}
} catch (Exception e) {
log.error("本地檔案上傳FTP失敗", e);
e.printStackTrace();
ExceptionUtil.recordErrorMsg(e);
} finally {
IOUtils.closeQuietly(fis);
closeConnect();
}
}
return flag;
}
/**
* 根據指定目錄獲取該目錄下的檔名稱
*
* @param ftpPath
* @return
*/
public List<String> getFileNameListByPath(String ftpPath) {
List<String> fileList = new ArrayList<>();
// 登入
login(ftp_address, Integer.parseInt(ftp_port), ftp_username, ftp_password);
if (ftpClient != null) {
ftpClient.setBufferSize(Integer.parseInt(buffer_size));
try {
if (ftpPath != null && ftpPath != "") {
String path = changeEncoding(base_path + ftpPath);
// 判斷是否存在該目錄
if (!ftpClient.changeWorkingDirectory(path)) {
log.error(base_path + ftpPath + "該目錄不存在");
return fileList;
}
}
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.enterLocalPassiveMode(); // 設定被動模式,開通一個埠來傳輸資料
ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
String[] fs = ftpClient.listNames();
if (fs != null && fs.length > 0) {
for (String string : fs) {
fileList.add(new String(string.getBytes(serverCharset), localCharset));
}
return fileList;
}
} catch (Exception e) {
e.printStackTrace();
log.error("下載檔案失敗", e);
ExceptionUtil.recordErrorMsg(e);
} finally {
closeConnect();
}
}
return fileList;
}
/**
* 下載指定檔案到本地
*
* @param ftpPath
* FTP伺服器檔案相對路徑,例如:test/123
* @param fileName
* 要下載的檔名,例如:test.txt
* @param savePath
* 儲存檔案到本地的路徑,例如:D:/test
* @return 成功返回true,否則返回false
*/
public boolean downloadFile(String ftpPath, String fileName, String savePath) {
// 登入
login(ftp_address, Integer.parseInt(ftp_port), ftp_username, ftp_password);
boolean flag = false;
if (ftpClient != null) {
// 設定緩衝區大小
ftpClient.setBufferSize(Integer.parseInt(buffer_size));
try {
if (ftpPath != null && ftpPath != "") {
String path = changeEncoding(base_path + ftpPath);
// 判斷是否存在該目錄
if (!ftpClient.changeWorkingDirectory(path)) {
log.error(base_path + ftpPath + "該目錄不存在");
return flag;
}
}
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.enterLocalPassiveMode(); // 設定被動模式,開通一個埠來傳輸資料
ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
String[] fs = ftpClient.listNames();
// 判斷該目錄下是否有檔案
if (fs == null || fs.length == 0) {
log.error(base_path + ftpPath + "該目錄下沒有檔案");
return flag;
}
for (String ff : fs) {
String ftpName = new String(ff.getBytes(serverCharset), localCharset);
if (ftpName.equals(fileName)) {
File file = new File(savePath + '/' + ftpName);
try (OutputStream os = new FileOutputStream(file)) {
flag = ftpClient.retrieveFile(ff, os);
} catch (Exception e) {
log.error(e.getMessage(), e);
e.printStackTrace();
ExceptionUtil.recordErrorMsg(e);
}
break;
}
}
} catch (Exception e) {
e.printStackTrace();
log.error("下載檔案失敗", e);
e.printStackTrace();
ExceptionUtil.recordErrorMsg(e);
} finally {
closeConnect();
}
}
return flag;
}
/**
* 獲取ftp目錄下所有檔案
*
* @param ftpPath
* @return
*/
public FTPFile[] getAllFiles(String ftpPath) {
// 登入
login(ftp_address, Integer.parseInt(ftp_port), ftp_username, ftp_password);
if (ftpClient != null) {
try {
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
String path = changeEncoding(base_path + ftpPath);
// 判斷是否存在該目錄
if (!ftpClient.changeWorkingDirectory(path)) {
log.error(base_path + ftpPath + "該目錄不存在");
return null;
}
ftpClient.enterLocalPassiveMode(); // 設定被動模式,開通一個埠來傳輸資料
FTPFile[] fs = ftpClient.listFiles();
// FTPFileEntryParser
// ftpClient.initiateListParsing("NETWARE",path);
// ftpClient.setParserFactory(new OSSFTPFileEntryParserFactory());
// FTPFile[] fs = ftpClient.listFiles("./", new FTPFileFilter() {
// @Override
// public boolean accept(FTPFile file) {
// // System.out.println(file.getName());
// return true;
// }
// });
System.out.println("fs.length" + fs.length);
// 判斷該目錄下是否有檔案
if (fs == null || fs.length == 0) {
log.error(base_path + ftpPath + "該目錄下沒有檔案");
return null;
}
return fs;
} catch (IOException e) {
log.error("獲取檔案失敗", e);
} finally {
closeConnect();
}
}
return null;
}
/**
* 根據名稱獲取檔案,以輸入流返回
*
* @param ftpPath
* FTP伺服器上檔案相對路徑,例如:test/123
* @param fileName
* 檔名,例如:test.txt
* @return InputStream 輸入流物件
*/
public InputStream getInputStreamByName(String ftpPath, String fileName) {
// 登入
login(ftp_address, Integer.parseInt(ftp_port), ftp_username, ftp_password);
InputStream input = null;
if (ftpClient != null) {
// 設定緩衝區大小
ftpClient.setBufferSize(Integer.parseInt(buffer_size));
try {
String path = changeEncoding(base_path + ftpPath);
// 判斷是否存在該目錄
if (!ftpClient.changeWorkingDirectory(path)) {
log.error(base_path + ftpPath + "該目錄不存在");
return input;
}
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.enterLocalPassiveMode(); // 設定被動模式,開通一個埠來傳輸資料
ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
String[] fs = ftpClient.listNames();
// 判斷該目錄下是否有檔案
if (fs == null || fs.length == 0) {
log.error(base_path + ftpPath + "該目錄下沒有檔案");
return input;
}
boolean fileIsExit = false;
for (String ff : fs) {
String ftpName = new String(ff.getBytes(serverCharset), localCharset);
if (ftpName.equals(fileName)) {
input = ftpClient.retrieveFileStream(ff);
byte[] bytes = IOUtils.toByteArray(input);
input = new ByteArrayInputStream(bytes);
ftpClient.completePendingCommand();
fileIsExit = true;
break;
}
}
if (!fileIsExit) {
return input;
}
} catch (IOException e) {
log.error("獲取檔案失敗", e);
} finally {
closeConnect();
}
}
return input;
}
/**
* 刪除指定檔案
*
* @param filePathAndFileName
* 檔案相對路徑,例如:test/123/test.txt
* @return 成功返回true,否則返回false
*/
public boolean deleteFile(String filePathAndFileName) {
// 登入
login(ftp_address, Integer.parseInt(ftp_port), ftp_username, ftp_password);
boolean flag = false;
if (ftpClient != null) {
try {
String path = changeEncoding(base_path + filePathAndFileName);
ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
flag = ftpClient.deleteFile(path);
} catch (IOException e) {
log.error("刪除檔案失敗", e);
e.printStackTrace();
ExceptionUtil.recordErrorMsg(e);
} finally {
closeConnect();
}
}
return flag;
}
/**
* 連線FTP伺服器
*
* @param address
* 地址,如:127.0.0.1
* @param port
* 埠,如:21
* @param username
* 使用者名稱,如:root
* @param password
* 密碼,如:root
*/
private void login(String address, int port, String username, String password) {
ftpClient = new FTPClient();
try {
ftpClient.connect(address, port);
ftpClient.login(username, password);
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
int reply = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
closeConnect();
log.error("FTP伺服器連線失敗");
}
System.out.println("FTP登入成功");
} catch (Exception e) {
log.error("FTP登入失敗", e);
}
}
/**
* 關閉FTP連線
*
*/
private void closeConnect() {
if (ftpClient != null && ftpClient.isConnected()) {
try {
ftpClient.logout();
ftpClient.disconnect();
} catch (IOException e) {
log.error("關閉FTP連線失敗", e);
}
}
}
/**
* FTP伺服器路徑編碼轉換
*
* @param ftpPath
* FTP伺服器路徑
* @return String
*/
private String changeEncoding(String ftpPath) {
String directory = null;
try {
if (FTPReply.isPositiveCompletion(ftpClient.sendCommand(OPTS_UTF8, "ON"))) {
localCharset = CHARSET_UTF8;
}
directory = new String(ftpPath.getBytes(localCharset), serverCharset);
} catch (Exception e) {
log.error("路徑編碼轉換失敗", e);
}
return directory;
}
/**
* 在伺服器上遞迴建立目錄
*
* @param dirPath
* 上傳目錄路徑
* @return
*/
private void createDirectorys(String dirPath) {
try {
if (!dirPath.endsWith("/")) {
dirPath += "/";
}
String directory = dirPath.substring(0, dirPath.lastIndexOf("/") + 1);
ftpClient.makeDirectory("/");
int start = 0;
int end = 0;
if (directory.startsWith("/")) {
start = 1;
} else {
start = 0;
}
end = directory.indexOf("/", start);
while (true) {
String subDirectory = new String(dirPath.substring(start, end));
if (!ftpClient.changeWorkingDirectory(subDirectory)) {
if (ftpClient.makeDirectory(subDirectory)) {
ftpClient.changeWorkingDirectory(subDirectory);
} else {
log.info("建立目錄失敗");
return;
}
}
start = end + 1;
end = directory.indexOf("/", start);
// 檢查所有目錄是否建立完畢
if (end <= start) {
break;
}
}
} catch (Exception e) {
log.error("上傳目錄建立失敗", e);
}
}
}
補充yml配置如下:
#FTP登入 上傳 下載相關配置
ftp:
ftp_address: 192.163.20.155
ftp_port: 21
ftp_username: bohua1
ftp_password: BHsoft13579!
localCharset: UTF-8
serverCharset: ISO-8859-1
buffer_size: 42680320