我只是在我的应用程序中“解决”了这个问题,并认为我会分享我学到的东西。
我研究了 RESUME 是如何工作的,发现它取决于您使用的方法。对我来说,我同时使用了 PipedInputStream 和 PipedOutputStream,因为我可能正在向本地文件传输/从本地文件传输,甚至从远程服务器传输到/从远程服务器传输。
我发现对我来说,我将我的 PipedOutputStream 提供给 get 方法,但没有提供模式(默认为 OVERWRITE),然后将我的 PipedInputStream 提供给 put 方法,参数为 RESUME。put 方法使我的 InputStream 的字节数等于我发送到的文件的当前大小。
这需要一段时间,因为我已经在推进 PipedOutputStream X 个字节数,然后 PipedInputStream 正在推进另一个 X 个字节,我得到了很大的差距。我通过查看ChannelSftp 源代码发现了这一点
当然,如果您不做与我完全相同的事情,情况会有所不同,但如果您的来源或目的地是本地的,您可能不需要担心这一点。如果你不知道你是怎么做的,我会尝试查看源代码。
我正在使用 Grails,所以这可能不适合你,但这就是我所做的
/*
* This was initially copied from
* <a href="http://www.intelligrape.com/blog/2013/04/04/using-ftp-with-grails/">
* http://www.intelligrape.com/blog/2013/04/04/using-ftp-with-grails/</a> for
* the basic structure. JavaDoc and additional method were added as needed.
*
* @author Puneet Behl
* @author jonathan.tinsman
*/
class FtpService {
/**
* Gets the file from the server and loads it into the provided output stream
*
* @param outputStream
* - the output stream to have the file loaded to
* @param fileName
* - the desired file
* @param ftpCredential
* -the server credentials
*/
def load(OutputStream outputStream, String fileName, FtpCredential ftpCredential) {
connect(ftpCredential) { ChannelSftp sftp ->
sftp.get fileName, outputStream, new FtpMonitor()
}
}
/**
* Writes the file on the server
*
* @param inputStream
* - the input stream for writing
* @param fileName
* - the file name
* @param mode
* - the mode for the transfer (defaults to {@link ChannelSftp#OVERWRITE}
* @param ftpCredential
* - the server credentials
*/
def save(InputStream inputStream, String fileName, Integer mode = ChannelSftp.OVERWRITE, FtpCredential ftpCredential) {
connect(ftpCredential) { ChannelSftp sftp ->
sftp.put inputStream, fileName, mode
}
}
/**
* Transfers the file from the input server to the output server.
* <p>
* The usage of {@link PipedInputStream} and {@link PipedOutputStream} is
* from <a href="http://ostermiller.org/convert_java_outputstream_inputstream.html">OsterMiller.org</a>
*
* @param fileName
* - the file name
* @param inputFtpCredential
* - the input server
* @param outputFtpCredential
* - the output server
* @param mode
* - the mode for the transfer (defaults to {@link ChannelSftp#OVERWRITE}
*/
def transfer(String fileName, FtpCredential inputFtpCredential, FtpCredential outputFtpCredential, Integer mode = ChannelSftp.OVERWRITE) {
// To change the size of the buffer, add an int with the desired pipe
// size. The default is 1024
PipedInputStream input = new PipedInputStream();
PipedOutputStream output = new PipedOutputStream(input);
// Starting in different threads so they do not deadlock each other
new Thread(
new Runnable(){
public void run(){
new FtpService().load output, fileName, inputFtpCredential
}
}
).start();
/*
* only passing the mode to the "save" as the save will progress the
* input stream on it's own.
*
* If we pass the mode to the "load" method, then there will be a gap
* in the data as the "load" will progress the stream xx bytes and the
* "save" will progress it another xx bytes (the size of the existing
* file).
*/
save input, fileName, mode, outputFtpCredential
}
/**
* Connect to the server and call the provided ChannelSftp Closure.
*
* @param ftpCredential
* - the server to connect to
* @param closure
* - the closure to call
* @param disconnectOnFinish
* - to disconnect the Session when the Closure is done (defaults to true)
*/
private def connect(FtpCredential ftpCredential, Closure closure, boolean disconnectOnFinish = true) {
Session session = null
ChannelSftp sftp = null
try {
JSch jSch = new JSch()
session = jSch.getSession ftpCredential?.username, ftpCredential?.server, ftpCredential?.port
session.setConfig "StrictHostKeyChecking", "no"
if (ftpCredential?.password) {
session.password = ftpCredential?.password
} else {
File keyFile = new File("${grailsApplication.config.pathToKeyFile}")
jSch.addIdentity(keyFile?.absolutePath)
}
session.connect()
Channel sFtpChannel = session.openChannel "sftp"
sFtpChannel.connect()
sftp = sFtpChannel as ChannelSftp
sftp.cd ftpCredential?.remoteBaseDir
closure.call sftp
} catch (Exception ex) {
ex.printStackTrace()
} finally {
if (disconnectOnFinish) {
sftp?.exit()
session?.disconnect()
}
}
}
}