When transferring files over SFTP using JSch, resuming partially transferred files (either uploads or downloads) can be implemented by handling offsets for files that are already partially transferred.
This guide explains how to:
- Resume downloads by continuing from the last transferred byte of a local file.
- Resume uploads by appending to a remote file.
Handling Download with Resume Support
To resume a download:
- Check the current size of the local file.
- Skip already downloaded bytes from the remote file using
InputStream.skip()
. - Append remaining content to the local file.
Code for Resuming Download
package org.kodejava.jsch;
import com.jcraft.jsch.*;
import java.io.*;
public class SFTPResumeDownload {
public static void main(String[] args) {
String host = "sftp.example.com";
String username = "user";
String password = "password";
String localFile = "local/path/to/file.txt";
String remoteFile = "/remote/path/to/file.txt";
JSch jsch = new JSch();
Session session = null;
ChannelSftp sftpChannel = null;
try {
// Setup SFTP connection
session = jsch.getSession(username, host, 22);
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "no"); // Disable key checking
session.connect();
Channel channel = session.openChannel("sftp");
channel.connect();
sftpChannel = (ChannelSftp) channel;
// Resume download logic
File file = new File(localFile);
long localFileSize = file.exists() ? file.length() : 0;
long remoteFileSize = sftpChannel.lstat(remoteFile).getSize();
if (localFileSize >= remoteFileSize) {
System.out.println("File already fully downloaded.");
return;
}
try (InputStream inputStream = sftpChannel.get(remoteFile);
OutputStream outputStream = new FileOutputStream(file, true)) {
inputStream.skip(localFileSize); // Skip downloaded portion
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
System.out.println("Download resumed and completed.");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sftpChannel != null) sftpChannel.disconnect();
if (session != null) session.disconnect();
}
}
}
Handling Upload with Resume Support
To resume an upload:
- Check the size of the remote file.
- Skip already uploaded bytes from the local file.
- Use the
ChannelSftp.APPEND
flag to append remaining bytes to the remote file.
Code for Resuming Upload
public static void resumeUpload(ChannelSftp sftpChannel, String localFile, String remoteFile) throws SftpException, IOException {
File file = new File(localFile);
long remoteFileSize = 0;
try {
remoteFileSize = sftpChannel.lstat(remoteFile).getSize(); // Check remote file size
} catch (SftpException e) {
System.out.println("Remote file does not exist. Starting upload from the beginning.");
}
System.out.println("Resuming upload from byte: " + remoteFileSize);
try (InputStream inputStream = new FileInputStream(file)) {
inputStream.skip(remoteFileSize); // Skip already uploaded bytes
// Append mode upload
sftpChannel.put(inputStream, remoteFile, ChannelSftp.APPEND);
System.out.println("Resume upload completed.");
}
}
Explanation of Key Steps
- Session Setup:
- A secure session is established with the SFTP server using user credentials.
StrictHostKeyChecking
is disabled for simplicity, but proper key validation is recommended for production.
- Resume Logic:
- Download: The remote file is read as an
InputStream
, skipping already downloaded bytes. The local file is opened in append mode. - Upload: The local file is read as an
InputStream
, skipping already uploaded bytes, and theput
method withChannelSftp.APPEND
is used to continue the upload.
- Download: The remote file is read as an
- Error Handling:
- If the remote file or local file does not exist, appropriate error handling ensures either the upload/download starts from the beginning or exits gracefully.
- File Integrity: To ensure file integrity, consider validating the file with hash checks or checksums after transfer.
Notes
- Increase the buffer size (
byte[] buffer = new byte[1024]
) for better performance for larger files. - Consider implementing retries or reconnect logic if the SFTP session disconnects during a transfer.
- Always confirm proper permissions for writing to the destination and reading from the source.
Conclusion
The above solution demonstrates how to implement resumable file transfer via SFTP using JSch. It ensures efficient and reliable file transfers by avoiding redundant retransmission of already transferred data.
Maven Dependencies
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>