ftpclient 指定远端路径_java上传下载支持ftp远程及本地目录(二)

本文介绍了如何在Java中使用FTPClient进行FTP资源的上传和下载,包括建立连接、切换或创建目录、上传资源以及下载资源的详细步骤。文章还提到了使用`ftpClient.completePendingCommand()`的重要性,并预告了如何实现FTP连接的线程池以提高效率。
摘要由CSDN通过智能技术生成

回顾

第一章讲到,通过建立简单工厂,来实现对调用层的封装,实现了工厂、接口、本地上传代码的实现。

这一节我们将讨论在java中,如果通过FTP上传、下载资源。

依赖

我们通过引入commons-net依赖,使用FTPClient来进行相应上传下载操作。

commons-net

commons-net

3.6

如何使用:

我们考虑下,要上传一个ftp资源要进行的主要步骤

1、建立连接

2、进入资源目录、或者创建

3、上传、下载资源

4、关闭连接

建立连接

//创建ftp对象

FTPClient ftpClient = new FTPClient();

//构建用户名、密码并连接程序

ftpClient.connect(props.getHost(), props.getPort());

ftpClient.login(props.getUsername(), props.getPassword());

log.info("连接FTP服务器返回码{}", ftpClient.getReplyCode());

//设置buffer大小

ftpClient.setBufferSize(props.getBufferSize());

//设置传输为二进制流

ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);

//设置为被动模式,客户端通知服务器打开传输端口,由客户端连接到服务器进行数据传输,

//默认为主动模式,采用采用被动模式的原因在于,可能本地端口无法正常打开,导致程序卡死

ftpClient.enterLocalPassiveMode();

//判定是否连接成功

int reply = ftpClient.getReplyCode();

if (!FTPReply.isPositiveCompletion(reply)) {

throw new Exception("失败相应状态码"+reply);

}

return ftpClient

以上代码为建立连接过程,需要远程地址、端口、用户名、密码信息。

创建、进入目录

进入核心方法:

ftpClient.changeWorkingDirectory(pathName);

创建目录方法:

ftpClient.makeDirectory(pathName)

通过以上两个核心方法实现目录切换和创建

//通过hashmap缓存路径,减少客户端查询服务器的次数,目录无删除操作,故可采用此方法,

//如果有删除且为分布式,考虑使用redis缓存

private static ConcurrentHashMap pathMap=new ConcurrentHashMap<>();

/**

* 判定目录是否为空,并切换目录

*/

private static void checkAndCreate(String pathName,FTPClient ftpClient) throws IOException {

//增加缓存机制,无须重复上服务器检测。

if(pathMap.containsKey(pathName)) {

//切换目录

ftpClient.changeWorkingDirectory(pathName);

return;

}

//检出目录是否存在,如果存在,则加入缓存

if(ftpClient.changeWorkingDirectory(pathName)){

pathMap.put(pathName,true);

}else {

//尝试创建目录,创建失败,则递归创建父级目录

if (ftpClient.makeDirectory(pathName)) {

pathMap.put(pathName, true);

} else {

//进行上级创建

int splitIndex = pathName.lastIndexOf("/");

String prePath = pathName.substring(0, splitIndex);

checkAndCreate(prePath, ftpClient);

checkAndCreate(pathName, ftpClient);

}

ftpClient.changeWorkingDirectory(pathName);

}

}

上传资源

try (OutputStream out = ftpClient.storeFileStream(encodingPath(reallyFileName))) {

out.write(file.getBytes());

return true;

}

catch (IOException ex){

log.error("IO写入异常"+ex);

return false;

}

catch (Exception ex) {

log.error("写入异常"+ex);

return false;

}

finally {

ftpClient.completePendingCommand();

//这里使用了数据池,把对象放回池子。后续介绍

releaseFtpClient(ftpClient);

}

注意:上面方法中的使用了ftpClient.completePendingCommand();方法,具体使用时机及原因详见:FTPClient中使用completePendingCommand方法注意事项

下载资源

try (InputStream in = ftpClient.retrieveFileStream(encodingPath(fileName));

OutputStream out = response.getOutputStream())

{

int size = 0;

byte[] buf = new byte[10240];

while ((size = in.read(buf)) > 0) {

out.write(buf, 0, size);

out.flush();

}

} finally {

ftpClient.completePendingCommand();

releaseFtpClient(ftpClient);

}

同理上传相似,不过下载的时候我们没有一次读取出来,而是通过循环,边读取,边写入客户端,这样可以提升传输效率

一个复用性问题

我们知道,线程有线程池,数据库有连接池,ftp新建连接每次都重新连接,显然效率低下,我们如何简单的实现一个自己的ftp线程池呢?

下一章将会讲到。

参考资料

【特此声明:本文原创,禁止转载!觉得有用打赏一个吧】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值