java上传文件到sftp服务器
最近公司有个数据对接需求,合作方那边是使用我们这边的系统进行出单的,数据首先也是在我们这边。
后面他们自己开发了业务系统,需要我们这边定时把每天的数据传送到那边去。
他们那边开发部门要求我们这边,按一定的格式导出加签加密的数据文件到他们的sftp服务器上面去。
sftp代码之前同事有写过类似的代码,就把他的给我啦,既然有了代码,当然要消化成自己的知识啦!
这个过程中也遇到一些坑,就是我们上传到sftp目录的时候,文件一多我们就得隔开文件夹,一般都是按年月隔开的,但是sftp切换目录后,如果目录不存在,我们就新建目录,这样的逻辑是没毛病,但是它没办法一次建多级目录,比如/home 下面可以建/home/2022/ 没办法建/home/2022/03(会报异常),所以这个的话我们还得用循环来做。
代码
先给大家看下代码:
string username = "";//账号
string password = ""; //密码
string host = ""; //ip
int port=8889; //端口号
string sftpurl = "/application/data"; //上传到sftp服务器 路径
string publicurl = "e://"; //要上传的文件
string yyyy = dateutils.formatdate(new date(), "yyyy");
string mm = dateutils.formatdate(new date(), "mm");
string uploadurl = sftpurl + "/" + yyyy + "/" + mm;
//存储目录地址
list dirs = new arraylist();
dirs.add(0, sftpurl + "/" + yyyy + "/");
dirs.add(1, sftpurl + "/" + yyyy + "/" + mm + "/");
try {
//1.获取会话
jsch jsch = new jsch();
session session = jsch.getsession(username, host, port);
session.setpassword(password);
properties properties = new properties();
properties.put("stricthostkeychecking", "no");
session.setconfig(properties);
session.connect();
//2.获取上传的管道
channel channel = session.openchannel("sftp");
channel.connect();
sftp = (channelsftp) channel;
if (!(uploadurl == null || uploadurl.trim().length() == 0)) {
for (int index = 0; index < dirs.size(); index++) {
//目录不存在,新建目录
try {
sftp.cd(uploadurl);//进入指定目录
break;
} catch (sftpexception e1) {
try {
sftp.cd(dirs.get(index).tostring());
} catch (sftpexception e2) {
try {
sftp.mkdir(dirs.get(index).tostring());
sftp.cd(dirs.get(index).tostring());
} catch (sftpexception e3) {
logger.error("sftp切换目录出错!", e3);
}
}
}
}
}
//读取源文件流(客户端文件)
inputstream client_fileinput = new fileinputstream(publicurl );
sftp.put(client_fileinput, “上传后的文件名”);
//传送到服务端
//5.关闭
sftp.disconnect();
client_fileinput.close();
channel.disconnect();
session.disconnect();
logger.info("sftp传输成功");
} catch (exception e) {
logger.info("sftp传输失败: " + e.tostring());
e.printstacktrace();
}
一般上传完文件后,需要删除本地的文件以免占用空间
/**
* 迭代删除文件夹
* @param dirpath 文件夹路径
*/
public static void deletedir(string dirpath) {
file file = new file(dirpath);
if(!file.exists()){
return;
}
if(file.isfile())
{
file.delete();
}else {
file[] files = file.listfiles();
if(files == null) {
file.delete();
}else {
for (int i = 0; i < files.length; i++) {
deletedir(files[i].getabsolutepath());
}
file.delete();
}
}
}
这里我遇到个坑,就是你们发现文件夹或者文件没删除或者没删除干净,就要检查一下流有没有关闭,传递流的时候最好不要直接 xxx方法(new fileinputstream),用下面这种方式比较好,好排查问题,哈哈。
fileinputstream file=new fileinputstream(“”); xxx方法(file);file.close();
sftp连接过程
2.1、jsch简介
jsch库可以实现java连接linux服务器并操作命令、文件等,支持常用的各种授权模式。
3.1、jsch建立会话连接
从jsch对象中获取session,用于连接,并设置连接信息,账号、密码、服务器地址、端口号。
3.2 、设置连接的参数配置
stricthostkeychecking=no 最不安全的级别,当然也没有那么多烦人的提示了,相对安全的内网测试时建议使用。如果连接server的key在本地不存在,那么就自动添加到文件中(默认是known_hosts),并且给出一个警告。 stricthostkeychecking=ask 默认的级别。如果连接和key不匹配,给出提示,并拒绝登录。 stricthostkeychecking=yes 最安全的级别,如果连接与key不匹配,就拒绝连接,不会提示详细信息。
3.3、获取文件上传的通道
通过以上的步骤,我们与sftp服务器建立了连接后,我们需要获取文件的传输通道channel,并指定为sftp服务,随便进行connect()连接。
3.3、常用命令
获取了sftp通道,我们可以类似在linux下简单做一些shell指令操作:
mkdir()方法 创建目录,只允许创建一级目录cd()方法 切换目录put()方法 上传文件rm()方法 删除文件
还有很多,大家可以直接看对象的对应方法就知道了,方法命名跟我们平时用的linux命令差不多。
用完一定要记得关闭各种连接跟流呀!!!!!!
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论