How do I transfer files with resume support over SFTP using JSch?

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:

  1. Check the current size of the local file.
  2. Skip already downloaded bytes from the remote file using InputStream.skip().
  3. 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:

  1. Check the size of the remote file.
  2. Skip already uploaded bytes from the local file.
  3. 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

  1. 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.
  2. 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 the put method with ChannelSftp.APPEND is used to continue the upload.
  3. 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.
  4. 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>

Maven Central

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.