JSch 的 ChannelSftp 一次不会下载多个文件
JSch's ChannelSftp doesn't download more than one file at a time
令人沮丧的是 JSch 没有抛出正常消息的异常。我正在尝试下载一组文件作为 InputStreams。下载文件的代码非常简单:
@Override
@SneakyThrows
public InputStream getInputStream(String path) {
return channelSftp.get(path);
}
我有这个用于下载 InputStream 并将其转换为 DataPages 的文件 URL 列表:
List<DataPage> dataPages =
files.stream()
.map(
fileName -> {
String fileURL = folderUrl[0] + "/" + fileName;
return client.getInputStream(fileURL);
})
.map(dataPageFunction)
.collect(Collectors.toList());
第一个文件下载成功。当我们得到第二个文件时,问题就出现了。我启用了日志来发现我是否发现了什么,但我唯一得到的是:
2022-04-13T10:58:27.916Z INFO [Connect thread localhost session] i.s.c.e.c.SftpClient$JschLogger:158 Caught an exception, leaving main loop due to Socket closed
我尝试了另一种获取文件的方法:
@SneakyThrows
public Stream<InputStream> getInputStreams(String folderURL, String filePattern) {
Vector<ChannelSftp.LsEntry> lsEntries = channelSftp.ls(folderURL + "/" + filePattern);
return lsEntries.stream()
.map(
entry -> {
Optional<InputStream> is = Optional.empty();
try {
is = Optional.of(channelSftp.get(folderURL + "/" + entry.getFilename()));
} catch (SftpException e) {
log.error(e.getMessage());
}
return is;
})
.filter(Optional::isPresent)
.map(Optional::get);
}
如前所述,第一个文件已成功下载。总共有三个文件,channelSftp.get
第二个和第三个文件的方法失败。
打印的日志是:
2022-04-13T12:08:06.864Z ERROR [Test worker] i.s.c.e.c.SftpClient:132
2022-04-13T12:08:08.316Z ERROR [Test worker] i.s.c.e.c.SftpClient:132
堆栈跟踪只是:
4:
at app//com.jcraft.jsch.ChannelSftp._stat(ChannelSftp.java:2227)
at app//com.jcraft.jsch.ChannelSftp._stat(ChannelSftp.java:2242)
at app//com.jcraft.jsch.ChannelSftp.ls(ChannelSftp.java:1592)
at app//com.jcraft.jsch.ChannelSftp.ls(ChannelSftp.java:1553)
.
.
.
我想包括我的 open
和 close
配置以防万一:
@SneakyThrows
public void open() {
JSch jsch = new JSch();
JSch.setLogger(new JschLogger());
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
if (StringUtils.isNoneBlank(privateKey)) {
privateKey = SSHUtils.toRSA(privateKey, passphrase);
jsch.addIdentity(
"",
privateKey.getBytes(),
null,
Objects.nonNull(passphrase) ? passphrase.getBytes() : null);
}
session = jsch.getSession(username, server, Objects.nonNull(port) ? port : DEFAULT_PORT);
session.setConfig(config);
if (StringUtils.isNoneBlank(password)) session.setPassword(password);
session.connect();
channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect();
}
@SneakyThrows
public void close() {
if (Objects.nonNull(channelSftp) && channelSftp.isConnected()) channelSftp.disconnect();
if (Objects.nonNull(session) && session.isConnected()) session.disconnect();
}
我了解到 JSch 不太适合流。这个问题可以通过简单地遍历 lsEntries
.
来解决
@SneakyThrows
public List<InputStream> getInputStreams(String folderURL, String filePattern) {
Vector<ChannelSftp.LsEntry> lsEntries = channelSftp.ls(folderURL + "/" + filePattern);
List<InputStream> inputStreams = new ArrayList<>();
for (LsEntry entry : lsEntries) {
try {
inputStreams.add(channelSftp.get(folderURL + "/" + entry.getFilename()));
} catch (SftpException e) {
log.error(e.getMessage());
}
}
return inputStreams;
}
令人沮丧的是 JSch 没有抛出正常消息的异常。我正在尝试下载一组文件作为 InputStreams。下载文件的代码非常简单:
@Override
@SneakyThrows
public InputStream getInputStream(String path) {
return channelSftp.get(path);
}
我有这个用于下载 InputStream 并将其转换为 DataPages 的文件 URL 列表:
List<DataPage> dataPages =
files.stream()
.map(
fileName -> {
String fileURL = folderUrl[0] + "/" + fileName;
return client.getInputStream(fileURL);
})
.map(dataPageFunction)
.collect(Collectors.toList());
第一个文件下载成功。当我们得到第二个文件时,问题就出现了。我启用了日志来发现我是否发现了什么,但我唯一得到的是:
2022-04-13T10:58:27.916Z INFO [Connect thread localhost session] i.s.c.e.c.SftpClient$JschLogger:158 Caught an exception, leaving main loop due to Socket closed
我尝试了另一种获取文件的方法:
@SneakyThrows
public Stream<InputStream> getInputStreams(String folderURL, String filePattern) {
Vector<ChannelSftp.LsEntry> lsEntries = channelSftp.ls(folderURL + "/" + filePattern);
return lsEntries.stream()
.map(
entry -> {
Optional<InputStream> is = Optional.empty();
try {
is = Optional.of(channelSftp.get(folderURL + "/" + entry.getFilename()));
} catch (SftpException e) {
log.error(e.getMessage());
}
return is;
})
.filter(Optional::isPresent)
.map(Optional::get);
}
如前所述,第一个文件已成功下载。总共有三个文件,channelSftp.get
第二个和第三个文件的方法失败。
打印的日志是:
2022-04-13T12:08:06.864Z ERROR [Test worker] i.s.c.e.c.SftpClient:132
2022-04-13T12:08:08.316Z ERROR [Test worker] i.s.c.e.c.SftpClient:132
堆栈跟踪只是:
4:
at app//com.jcraft.jsch.ChannelSftp._stat(ChannelSftp.java:2227)
at app//com.jcraft.jsch.ChannelSftp._stat(ChannelSftp.java:2242)
at app//com.jcraft.jsch.ChannelSftp.ls(ChannelSftp.java:1592)
at app//com.jcraft.jsch.ChannelSftp.ls(ChannelSftp.java:1553)
.
.
.
我想包括我的 open
和 close
配置以防万一:
@SneakyThrows
public void open() {
JSch jsch = new JSch();
JSch.setLogger(new JschLogger());
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
if (StringUtils.isNoneBlank(privateKey)) {
privateKey = SSHUtils.toRSA(privateKey, passphrase);
jsch.addIdentity(
"",
privateKey.getBytes(),
null,
Objects.nonNull(passphrase) ? passphrase.getBytes() : null);
}
session = jsch.getSession(username, server, Objects.nonNull(port) ? port : DEFAULT_PORT);
session.setConfig(config);
if (StringUtils.isNoneBlank(password)) session.setPassword(password);
session.connect();
channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect();
}
@SneakyThrows
public void close() {
if (Objects.nonNull(channelSftp) && channelSftp.isConnected()) channelSftp.disconnect();
if (Objects.nonNull(session) && session.isConnected()) session.disconnect();
}
我了解到 JSch 不太适合流。这个问题可以通过简单地遍历 lsEntries
.
@SneakyThrows
public List<InputStream> getInputStreams(String folderURL, String filePattern) {
Vector<ChannelSftp.LsEntry> lsEntries = channelSftp.ls(folderURL + "/" + filePattern);
List<InputStream> inputStreams = new ArrayList<>();
for (LsEntry entry : lsEntries) {
try {
inputStreams.add(channelSftp.get(folderURL + "/" + entry.getFilename()));
} catch (SftpException e) {
log.error(e.getMessage());
}
}
return inputStreams;
}