Java使用SFTP连接

前言

在做一个需要Java后台生成大量的XML文件,上传到FTP服务器上,然后另外一个线程连上FTP一直查询上传的文件夹里面有多少个文件,并把文件名通过WebSocket带到页面上更新页面,同时也可以从FTP服务器上下载文件。。。。。

刚开始认为很简单,用Apache的工具FTPClient来做,结果连接不上FTP服务器,后来发现是我们的FTP服务器只支持SFTP协议。

上代码

最开始走的Ftp协议

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package com.lucent.demo.utils;

import org.apache.commons.net.ftp.FTPClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
* @author zhangxingrui
* @create 2018-10-31 9:59
**/
public class FtpUtil {

private static final Logger logger = LoggerFactory.getLogger(FtpUtil.class);

/**
* 以用户的姓名为key,FTPClient为对象保存起来
*/
private static Map<String, FTPClient> clients = new ConcurrentHashMap<>();

public static boolean login(String host, int port, String username, String password, String userId){
boolean isOk = false;
FTPClient ftpClient = new FTPClient();
try {
ftpClient.setControlEncoding("GBK");
ftpClient.connect(host, port);
isOk = ftpClient.login(username, password);
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.setBufferSize(1024 * 2);
ftpClient.setDataTimeout(30 * 1000);
clients.put(userId, ftpClient);
} catch (IOException e) {
logger.error(e.getMessage());
}
return isOk;
}

public static void logout(String userId){
if(!clients.containsKey(userId))
return;

FTPClient ftpClient = clients.get(userId);
if(!ftpClient.isConnected())
return;

try {
// 退出FTP服务器
ftpClient.logout();
} catch (IOException e) {
logger.error(e.getMessage());
} finally {
try {
// 关闭FTP服务器连接
ftpClient.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}



}

考虑到要做一个通用的工具,所以我们的程序应该对用户输入的FTP地址进行协议的判断,然后确定要用FTP还是SFTP。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package com.lucent.demo.utils;

import alu.mtosi.common.util.SftpChannel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException;
import com.lucent.demo.config.GeneralConstant;
import com.lucent.demo.domain.Ftp;
import javafx.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
* @author zhangxingrui
* @create 2018-10-31 9:59
**/
public class SftpUtil {

private static final Logger logger = LoggerFactory.getLogger(SftpUtil.class);

private static Map<String, Pair<SftpChannel, ChannelSftp>> map = new ConcurrentHashMap<>();

public static ChannelSftp getChannel(Ftp ftp){
SftpChannel sftpChannel = new SftpChannel();
ChannelSftp channelSftp = null;
try {
channelSftp = sftpChannel.getChannel( ftp.getHost(), ftp.getPort(),
ftp.getUsername(), ftp.getPassword(), 60000 );
Pair<SftpChannel, ChannelSftp> pair = new Pair<>(sftpChannel, channelSftp);
map.put(ftp.getUserId(), pair);
} catch (JSchException e) {
logger.error(e.getMessage());
}
return channelSftp;
}

public static ChannelSftp getSlaveChannel(Ftp ftp){
SftpChannel sftpChannel = new SftpChannel();
ChannelSftp channelSftp = null;
try {
channelSftp = sftpChannel.getChannel( ftp.getHost(), ftp.getPort(),
ftp.getUsername(), ftp.getPassword(), 60000 );
Pair<SftpChannel, ChannelSftp> pair = new Pair<>(sftpChannel, channelSftp);
map.put(ftp.getUserId() + GeneralConstant.STANDBY, pair);
} catch (JSchException e) {
logger.error(e.getMessage());
}
return channelSftp;
}

public static ChannelSftp getChannel(String userId){
Pair<SftpChannel, ChannelSftp> pair = map.get(userId);
return pair == null ? null : pair.getValue();
}

public static void quit(String userId){
if(!map.containsKey(userId))
return;

Pair<SftpChannel, ChannelSftp> pair = map.get(userId);
SftpChannel sftpChannel = pair.getKey();
ChannelSftp channelSftp = pair.getValue();
if(channelSftp.isConnected()){
channelSftp.quit();
}
try {
sftpChannel.closeChannel();
} catch (Exception e) {
logger.error(e.getMessage());
}
}

}

遇到的问题

做的过程中遇到了一个问题就是,同一个channelSftp,一个线程用它来做 ls 的操作,另外一个线程用它来做 get 的操作,get操作就会报错。我在想是不是不能同时做多个读取或者写入的动作。。。知道的朋友请留言告诉我,谢谢。

zhangxingrui wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!