记录一个在项目中用到的ftp工具
1.ftp概述
FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文件传输协议”。用于Internet上的控制文件的双向传输。同时,它也是一个应用程序(Application)。基于不同的操作系统有不同的FTP应用程序,而所有这些应用程序都遵守同一种协议以传输文件。–摘自百度
也就是说“ftp”是一种协议,用来在网络中传输文件,基于这种协议可以有一种应用:就是将文件从A处传输到B处,传输的过程是通过ftp协议完成的。
实际的使用场景是这样的,会存在一个东西叫做FTP服务端,同时存在另一个东西叫做FTP客户端,显而易见,客户端与服务器端建立连接后,客户端可以向服务器端上传或下载文件,也可以进行一些其他操作,例如新建一个文件夹,或者删除一个文件。好啦,再举一个生动的例子:某人在上海出差,要向北京总部传一个word文件,于是他想到了使用ftp方式,打开他的电脑,再打开FTP客户端工具(本人使用FileZilla),连接到总部的FTP服务器,然后点击上传按钮,文件就上传了,于此同时他发现总部的FTP服务器中有最近上映的新电影(枪版),果断下载,看之,愉快的周末结束了。这大概就是一般情况下ftp的应用场景了。所以,这里面有两个概念很重要:FTP服务端,FTP客户端。
windows系统下有许多FTP应用工具(本人使用FileZilla),使用这些工具可以很轻松的完成上述场景,但这不是本文讨论的重点,本文讨论的在java程序中如何对FTP服务端进行文件操作。
2.sftp概念
这里还需要提一下sftp的概念:sftp是Secure File Transfer Protocol的缩写,安全文件传送协议。可以为传输文件提供一种安全的网络的加密方法。sftp 与 ftp 有着几乎一样的语法和功能。SFTP 为 SSH的其中一部分,是一种传输档案至 Blogger 伺服器的安全方式。–同样摘自百度。姑且就理解为一种比ftp更安全一点的协议吧。在windows下使用工具实现操作与ftp一样,本次代码实现同样需要考虑。
3.代码部分
这段代码是在项目中抽象出来的一个工具类,形式为一个接口和两个实现类,接口定义了相关的文件操作方法,实现类分别是ftp的实现和sftp的实现。如下:
代码结构:
- IFtpHelper(ftp接口)
- SftpHelperImpl(sftp实现)
- StandardFtpHelperImpl(ftp实现)
具体代码:
IFtpHelper:
import java.io.OutputStream;
import java.util.Set;
public interface IFtpHelper {
/**
* 登陆ftp服务器(使用被动方式)
* @param host
* @param username
* @param password
* @param port
* @param timeout
*/
public void loginFtpServer(String host, String username, String password, int port, int timeout);
/**
*注销登陆
*/
public void logoutFtpServer();
/**
* 创建目录(warn: 不支持递归创建)
* @param directoryPath
*/
public void mkdir(String directoryPath);
/**
* 递归创建目录
* @param directoryPath
*/
public void mkDirRecursive(String directoryPath);
/**
* 根据ftp服务器上指定目录下的文件名,获得其输出流
* @param filePath
* @return
*/
public OutputStream getOutputStream(String filePath);
public String getRemoteFileContent(String filePath);
public Set<String> getAllFilesInDir(String dir, String prefixFileName);
/**
* 删除文件(不支持删除文件夹)
* @param filesToDelete
*/
public void deleteFiles(Set<String> filesToDelete);
public void completePendingCommand();
/**
* 向ftp目录中写入文件
* @param sourceFilePath
* @param targetFilePath
*/
public void localWriteToFtp(String sourceFilePath,String targetFilePath);
}
SftpHelperImpl:
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.chinawiserv.dsp.dcs.dc.common.exception.DataXException;
import com.jcraft.jsch.*;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTP;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.Vector;
public class SftpHelperImpl implements IFtpHelper {
private static final Logger LOG = LoggerFactory
.getLogger(SftpHelperImpl.class);
private Session session = null;
private ChannelSftp channelSftp = null;
@Override
public void loginFtpServer(String host, String username, String password,
int port, int timeout) {
JSch jsch = new JSch();
try {
this.session = jsch.getSession(username, host, port);
if (this.session == null) {
throw DataXException
.asDataXException(FtpWriterErrorCode.FAIL_LOGIN,
"创建ftp连接this.session失败,无法通过sftp与服务器建立链接,请检查主机名和用户名是否正确.");
}
this.session.setPassword(password);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
// config.put("PreferredAuthentications", "password");
this.session.setConfig(config);
this.session.setTimeout(timeout);
this.session.connect();
this.channelSftp = (ChannelSftp) this.session.openChannel("sftp");
this.channelSftp.connect();
} catch (JSchException e) {
if (null != e.getCause()) {
String cause = e.getCause().toString();
String unknownHostException = "java.net.UnknownHostException: "
+ host;
String illegalArgumentException = "java.lang.IllegalArgumentException: port out of range:"
+ port;
String wrongPort = "java.net.ConnectException: Connection refused";
if (unknownHostException.equals(cause)) {
String message = String
.format("请确认ftp服务器地址是否正确,无法连接到地址为: [%s] 的ftp服务器, errorMessage:%s",
host, e.getMessage());
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.FAIL_LOGIN, message, e);
} else if (illegalArgumentException.equals(cause)
|| wrongPort.equals(cause)) {
String message = String.format(
"请确认连接ftp服务器端口是否正确,错误的端口: [%s], errorMessage:%s",
port, e.getMessage());
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.FAIL_LOGIN, message, e);
}
} else {
String message = String
.format("与ftp服务器建立连接失败,请检查主机、用户名、密码是否正确, host:%s, port:%s, username:%s, errorMessage:%s",
host, port, username, e.getMessage());
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.FAIL_LOGIN, message);
}
}
}
@Override
public void logoutFtpServer() {
if (this.channelSftp != null) {
this.channelSftp.disconnect();
this.channelSftp = null;
}
if (this.session != null) {
this.session.disconnect();
this.session = null;
}
}
@Override
public void mkdir(String directoryPath) {
boolean isDirExist = false;
try {
this.printWorkingDirectory();
SftpATTRS sftpATTRS = this.channelSftp.lstat(directoryPath);
isDirExist = sftpATTRS.isDir();
} catch (SftpException e) {
if (e.getMessage().toLowerCase().equals("no such file")) {
LOG.warn(String.format(
"您的配置项path:[%s]不存在,将尝试进行目录创建, errorMessage:%s",
directoryPath, e.getMessage()), e);
isDirExist = false;
}
}
if (!isDirExist) {
try {
// warn 检查mkdir -p
this.channelSftp.mkdir(directoryPath);
} catch (SftpException e) {
String message = String
.format("创建目录:%s时发生I/O异常,请确认与ftp服务器的连接正常,拥有目录创建权限, errorMessage:%s",
directoryPath, e.getMessage());
LOG.error(message, e);
throw DataXException
.asDataXException(
FtpWriterErrorCode.COMMAND_FTP_IO_EXCEPTION,
message, e);
}
}
}
@Override
public void mkDirRecursive(String directoryPath){
boolean isDirExist = false;
try {
this.printWorkingDirectory();
SftpATTRS sftpATTRS = this.channelSftp.lstat(directoryPath);
isDirExist = sftpATTRS.isDir();
} catch (SftpException e) {
if (e.getMessage().toLowerCase().equals("no such file")) {
LOG.warn(String.format(
"您的配置项path:[%s]不存在,将尝试进行目录创建, errorMessage:%s",
directoryPath, e.getMessage()), e);
isDirExist = false;
}
}
if (!isDirExist) {
StringBuilder dirPath = new StringBuilder();
dirPath.append(IOUtils.DIR_SEPARATOR_UNIX);
String[] dirSplit = StringUtils.split(directoryPath, IOUtils.DIR_SEPARATOR_UNIX);
try {
// ftp server不支持递归创建目录,只能一级一级创建
for(String dirName : dirSplit){
dirPath.append(dirName);
mkDirSingleHierarchy(dirPath.toString());
dirPath.append(IOUtils.DIR_SEPARATOR_UNIX);
}
} catch (SftpException e) {
String message = String
.format("创建目录:%s时发生I/O异常,请确认与ftp服务器的连接正常,拥有目录创建权限, errorMessage:%s",
directoryPath, e.getMessage());
LOG.error(message, e);
throw DataXException
.asDataXException(
FtpWriterErrorCode.COMMAND_FTP_IO_EXCEPTION,
message, e);
}
}
}
public boolean mkDirSingleHierarchy(String directoryPath) throws SftpException {
boolean isDirExist = false;
try {
SftpATTRS sftpATTRS = this.channelSftp.lstat(directoryPath);
isDirExist = sftpATTRS.isDir();
} catch (SftpException e) {
if(!isDirExist){
LOG.info(String.format("正在逐级创建目录 [%s]",directoryPath));
this.channelSftp.mkdir(directoryPath);
return true;
}
}
if(!isDirExist){
LOG.info(String.format("正在逐级创建目录 [%s]",directoryPath));
this.channelSftp.mkdir(directoryPath);
}
return true;
}
@Override
public OutputStream getOutputStream(String filePath) {
try {
this.printWorkingDirectory();
String parentDir = filePath.substring(0,
StringUtils.lastIndexOf(filePath, IOUtils.DIR_SEPARATOR));
this.channelSftp.cd(parentDir);
this.printWorkingDirectory();
//对文件名进行拆分
String fileName = filePath.substring(filePath.lastIndexOf(File.separator)+1);
OutputStream writeOutputStream = this.channelSftp.put(fileName,
ChannelSftp.APPEND);
String message = String.format(
"打开FTP文件[%s]获取写出流时出错,请确认文件%s有权限创建,有权限写出等", filePath,
filePath);
if (null == writeOutputStream) {
throw DataXException.asDataXException(
FtpWriterErrorCode.OPEN_FILE_ERROR, message);
}
return writeOutputStream;
} catch (SftpException e) {
String message = String.format(
"写出文件[%s] 时出错,请确认文件%s有权限写出, errorMessage:%s", filePath,
filePath, e.getMessage());
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.OPEN_FILE_ERROR, message);
}
}
@Override
public String getRemoteFileContent(String filePath) {
try {
this.completePendingCommand();
this.printWorkingDirectory();
String parentDir = filePath.substring(0,
StringUtils.lastIndexOf(filePath, IOUtils.DIR_SEPARATOR));
this.channelSftp.cd(parentDir);
this.printWorkingDirectory();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(22);
this.channelSftp.get(filePath, outputStream);
String result = outputStream.toString();
IOUtils.closeQuietly(outputStream);
return result;
} catch (SftpException e) {
String message = String.format(
"写出文件[%s] 时出错,请确认文件%s有权限写出, errorMessage:%s", filePath,
filePath, e.getMessage());
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.OPEN_FILE_ERROR, message);
}
}
@Override
public Set<String> getAllFilesInDir(String dir, String prefixFileName) {
Set<String> allFilesWithPointedPrefix = new HashSet<String>();
try {
this.printWorkingDirectory();
@SuppressWarnings("rawtypes")
Vector allFiles = this.channelSftp.ls(dir);
LOG.debug(String.format("ls: %s", JSON.toJSONString(allFiles,
SerializerFeature.UseSingleQuotes)));
for (int i = 0; i < allFiles.size(); i++) {
LsEntry le = (LsEntry) allFiles.get(i);
String strName = le.getFilename();
if (strName.startsWith(prefixFileName)) {
allFilesWithPointedPrefix.add(strName);
}
}
} catch (SftpException e) {
String message = String
.format("获取path:[%s] 下文件列表时发生I/O异常,请确认与ftp服务器的连接正常,拥有目录ls权限, errorMessage:%s",
dir, e.getMessage());
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.COMMAND_FTP_IO_EXCEPTION, message, e);
}
return allFilesWithPointedPrefix;
}
@Override
public void deleteFiles(Set<String> filesToDelete) {
String eachFile = null;
try {
this.printWorkingDirectory();
for (String each : filesToDelete) {
LOG.info(String.format("delete file [%s].", each));
eachFile = each;
this.channelSftp.rm(each);
}
} catch (SftpException e) {
String message = String.format(
"删除文件:[%s] 时发生异常,请确认指定文件有删除权限,以及网络交互正常, errorMessage:%s",
eachFile, e.getMessage());
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.COMMAND_FTP_IO_EXCEPTION, message, e);
}
}
private void printWorkingDirectory() {
try {
LOG.info(String.format("current working directory:%s",
this.channelSftp.pwd()));
} catch (Exception e) {
LOG.warn(String.format("printWorkingDirectory error:%s",
e.getMessage()));
}
}
@Override
public void completePendingCommand() {
}
/**
* 向ftp目录中写入文件
* @param sourceFilePath
* @param targetFilePath
*/
@Override
public void localWriteToFtp(String sourceFilePath,String targetFilePath){
try(BufferedOutputStream bos = new BufferedOutputStream( this.getOutputStream(targetFilePath));
) {
Files.copy(Paths.get(sourceFilePath),bos);
} catch (IOException e) {
e.printStackTrace();
}
}
}
StandardFtpHelperImpl:
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.chinawiserv.dsp.dcs.dc.common.exception.DataXException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTP;
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 java.io.*;
import java.net.UnknownHostException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.Set;
public class StandardFtpHelperImpl implements IFtpHelper {
private static final Logger LOG = LoggerFactory
.getLogger(StandardFtpHelperImpl.class);
FTPClient ftpClient = null;
@Override
public void loginFtpServer(String host, String username, String password,
int port, int timeout) {
this.ftpClient = new FTPClient();
try {
// this.ftpClient.setControlEncoding(“UTF-8”);
// 不需要写死ftp server的OS TYPE,FTPClient getSystemType()方法会自动识别
// this.ftpClient.configure(new FTPClientConfig(FTPClientConfig.SYST_UNIX));
this.ftpClient.setDefaultTimeout(timeout);
this.ftpClient.setConnectTimeout(timeout);
this.ftpClient.setDataTimeout(timeout);
// 连接登录
this.ftpClient.connect(host, port);
this.ftpClient.login(username, password);
this.ftpClient.enterRemotePassiveMode();
this.ftpClient.enterLocalPassiveMode();
int reply = this.ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
this.ftpClient.disconnect();
String message = String
.format("与ftp服务器建立连接失败,host:%s, port:%s, username:%s, replyCode:%s",
host, port, username, reply);
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.FAIL_LOGIN, message);
}
String fileEncoding = "GBK";
if (FTPReply.isPositiveCompletion(ftpClient.sendCommand(
"OPTS UTF8", "ON"))) {// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码,否则就使用本地编码(GBK).
fileEncoding = "UTF-8";
}
this.ftpClient.setControlEncoding(fileEncoding);
} catch (UnknownHostException e) {
String message = String.format(
"请确认ftp服务器地址是否正确,无法连接到地址为: [%s] 的ftp服务器, errorMessage:%s",
host, e.getMessage());
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.FAIL_LOGIN, message, e);
} catch (IllegalArgumentException e) {
String message = String.format(
"请确认连接ftp服务器端口是否正确,错误的端口: [%s], errorMessage:%s", port,
e.getMessage());
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.FAIL_LOGIN, message, e);
} catch (Exception e) {
String message = String
.format("与ftp服务器建立连接失败,host:%s, port:%s, username:%s, errorMessage:%s",
host, port, username, e.getMessage());
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.FAIL_LOGIN, message, e);
}
}
@Override
public void logoutFtpServer() {
if (this.ftpClient.isConnected()) {
try {
this.ftpClient.logout();
} catch (IOException e) {
String message = String.format(
"与ftp服务器断开连接失败, errorMessage:%s", e.getMessage());
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.FAIL_DISCONNECT, message, e);
} finally {
if (this.ftpClient.isConnected()) {
try {
this.ftpClient.disconnect();
} catch (IOException e) {
String message = String.format(
"与ftp服务器断开连接失败, errorMessage:%s",
e.getMessage());
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.FAIL_DISCONNECT, message, e);
}
}
this.ftpClient = null;
}
}
}
@Override
public void mkdir(String directoryPath) {
String message = String.format("创建目录:%s时发生异常,请确认与ftp服务器的连接正常,拥有目录创建权限",
directoryPath);
try {
this.printWorkingDirectory();
boolean isDirExist = this.ftpClient
.changeWorkingDirectory(directoryPath);
if (!isDirExist) {
int replayCode = this.ftpClient.mkd(directoryPath);
message = String
.format("%s,replayCode:%s", message, replayCode);
if (replayCode != FTPReply.COMMAND_OK
&& replayCode != FTPReply.PATHNAME_CREATED) {
throw DataXException.asDataXException(
FtpWriterErrorCode.COMMAND_FTP_IO_EXCEPTION,
message);
}
}
} catch (IOException e) {
message = String.format("%s, errorMessage:%s", message,
e.getMessage());
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.COMMAND_FTP_IO_EXCEPTION, message, e);
}
}
@Override
public void mkDirRecursive(String directoryPath){
StringBuilder dirPath = new StringBuilder();
dirPath.append(IOUtils.DIR_SEPARATOR_UNIX);
String[] dirSplit = StringUtils.split(directoryPath, IOUtils.DIR_SEPARATOR_UNIX);
String message = String.format("创建目录:%s时发生异常,请确认与ftp服务器的连接正常,拥有目录创建权限", directoryPath);
try {
// ftp server不支持递归创建目录,只能一级一级创建
for(String dirName : dirSplit){
dirPath.append(dirName);
boolean mkdirSuccess = mkDirSingleHierarchy(dirPath.toString());
dirPath.append(IOUtils.DIR_SEPARATOR_UNIX);
if(!mkdirSuccess){
throw DataXException.asDataXException(
FtpWriterErrorCode.COMMAND_FTP_IO_EXCEPTION,
message);
}
}
} catch (IOException e) {
message = String.format("%s, errorMessage:%s", message,
e.getMessage());
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.COMMAND_FTP_IO_EXCEPTION, message, e);
}
}
public boolean mkDirSingleHierarchy(String directoryPath) throws IOException {
boolean isDirExist = this.ftpClient
.changeWorkingDirectory(directoryPath);
// 如果directoryPath目录不存在,则创建
if (!isDirExist) {
int replayCode = this.ftpClient.mkd(directoryPath);
if (replayCode != FTPReply.COMMAND_OK
&& replayCode != FTPReply.PATHNAME_CREATED) {
return false;
}
}
return true;
}
@Override
public OutputStream getOutputStream(String filePath) {
try {
this.printWorkingDirectory();
String parentDir = filePath.substring(0,
StringUtils.lastIndexOf(filePath, IOUtils.DIR_SEPARATOR));
this.ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
boolean flage = this.ftpClient.changeWorkingDirectory(parentDir);
if(!flage){
String message = String.format("请确认您的配置项path:[%s]存在,且配置的用户有权限进入", parentDir);
LOG.error(message);
throw DataXException.asDataXException(FtpWriterErrorCode.FILE_NOT_EXISTS, message);
}
this.printWorkingDirectory();
OutputStream writeOutputStream = this.ftpClient
.appendFileStream(new String(filePath.getBytes(), FTP.DEFAULT_CONTROL_ENCODING));
String message = String.format(
"打开FTP文件[%s]获取写出流时出错,请确认文件%s有权限创建,有权限写出等", filePath,
filePath);
if (null == writeOutputStream) {
throw DataXException.asDataXException(
FtpWriterErrorCode.OPEN_FILE_ERROR, message);
}
return writeOutputStream;
} catch (IOException e) {
String message = String.format(
"写出文件 : [%s] 时出错,请确认文件:[%s]存在且配置的用户有权限写, errorMessage:%s",
filePath, filePath, e.getMessage());
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.OPEN_FILE_ERROR, message);
}
}
@Override
public String getRemoteFileContent(String filePath) {
try {
this.completePendingCommand();
this.printWorkingDirectory();
String parentDir = filePath.substring(0,
StringUtils.lastIndexOf(filePath, IOUtils.DIR_SEPARATOR));
this.ftpClient.changeWorkingDirectory(parentDir);
this.printWorkingDirectory();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(22);
this.ftpClient.retrieveFile(filePath, outputStream);
String result = outputStream.toString();
IOUtils.closeQuietly(outputStream);
return result;
} catch (IOException e) {
String message = String.format(
"读取文件 : [%s] 时出错,请确认文件:[%s]存在且配置的用户有权限读取, errorMessage:%s",
filePath, filePath, e.getMessage());
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.OPEN_FILE_ERROR, message);
}
}
@Override
public Set<String> getAllFilesInDir(String dir, String prefixFileName) {
Set<String> allFilesWithPointedPrefix = new HashSet<String>();
try {
boolean isDirExist = this.ftpClient.changeWorkingDirectory(dir);
if (!isDirExist) {
throw DataXException.asDataXException(
FtpWriterErrorCode.COMMAND_FTP_IO_EXCEPTION,
String.format("进入目录[%s]失败", dir));
}
this.printWorkingDirectory();
FTPFile[] fs = this.ftpClient.listFiles(dir);
// LOG.debug(JSON.toJSONString(this.ftpClient.listNames(dir)));
LOG.debug(String.format("ls: %s",
JSON.toJSONString(fs, SerializerFeature.UseSingleQuotes)));
for (FTPFile ff : fs) {
String strName = ff.getName();
if (strName.startsWith(prefixFileName)) {
allFilesWithPointedPrefix.add(strName);
}
}
} catch (IOException e) {
String message = String
.format("获取path:[%s] 下文件列表时发生I/O异常,请确认与ftp服务器的连接正常,拥有目录ls权限, errorMessage:%s",
dir, e.getMessage());
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.COMMAND_FTP_IO_EXCEPTION, message, e);
}
return allFilesWithPointedPrefix;
}
@Override
public void deleteFiles(Set<String> filesToDelete) {
String eachFile = null;
boolean deleteOk = false;
try {
this.printWorkingDirectory();
for (String each : filesToDelete) {
LOG.info(String.format("delete file [%s].", each));
eachFile = each;
deleteOk = this.ftpClient.deleteFile(each);
if (!deleteOk) {
String message = String.format(
"删除文件:[%s] 时失败,请确认指定文件有删除权限", eachFile);
throw DataXException.asDataXException(
FtpWriterErrorCode.COMMAND_FTP_IO_EXCEPTION,
message);
}
}
} catch (IOException e) {
String message = String.format(
"删除文件:[%s] 时发生异常,请确认指定文件有删除权限,以及网络交互正常, errorMessage:%s",
eachFile, e.getMessage());
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.COMMAND_FTP_IO_EXCEPTION, message, e);
}
}
private void printWorkingDirectory() {
try {
LOG.info(String.format("current working directory:%s",
this.ftpClient.printWorkingDirectory()));
} catch (Exception e) {
LOG.warn(String.format("printWorkingDirectory error:%s",
e.getMessage()));
}
}
@Override
public void completePendingCommand() {
/*
* Q:After I perform a file transfer to the server,
* printWorkingDirectory() returns null. A:You need to call
* completePendingCommand() after transferring the file. wiki:
* http://wiki.apache.org/commons/Net/FrequentlyAskedQuestions
*/
try {
boolean isOk = this.ftpClient.completePendingCommand();
if (!isOk) {
throw DataXException.asDataXException(
FtpWriterErrorCode.COMMAND_FTP_IO_EXCEPTION,
"完成ftp completePendingCommand操作发生异常");
}
} catch (IOException e) {
String message = String.format(
"完成ftp completePendingCommand操作发生异常, errorMessage:%s",
e.getMessage());
LOG.error(message);
throw DataXException.asDataXException(
FtpWriterErrorCode.COMMAND_FTP_IO_EXCEPTION, message, e);
}
}
/**
* 向ftp目录中写入文件
* @param sourceFilePath
* @param targetFilePath
*/
@Override
public void localWriteToFtp(String sourceFilePath,String targetFilePath){
try(BufferedOutputStream bos = new BufferedOutputStream(this.getOutputStream(targetFilePath));
) {
Files.copy(Paths.get(sourceFilePath),bos);
} catch (IOException e) {
e.printStackTrace();
}
}
}