The following post is aimed at familiarizing our readers with writing Java code to ultimately be able to connect and interact with SFTP servers. SFTP is a commonly used, standard, and secure protocol, that's main objective is to provide safe file and data transfer. When setting up a connection with the server, there are only a few simple steps to learn and we hope that by the end of this post, you'll know how to do them with your eyes closed.

Requirements

There are several Java libraries that can be used to connect to SFTP servers. We’ll be using Jsch, a pure Java implementation of SSH2. The following examples are just some of the number of ways to add JSCH to your java project:

Using Maven:

<dependency>
    <groupId>com.github.mwiede</groupId>
    <artifactId>jsch</artifactId>
    <version>0.2.0</version>
</dependency>

Using Gradle:

implementation 'com.github.mwiede:jsch:0.2.0'

Connecting to SFTP

For the sake of this post, we’ll be using an environment variable named SFTPTOGO_URL that contains all of the information required to connect to an SFTP server in a URI format: sftp://user:password@host. The variable is parsed in order to extract the URI parts using URI.parse, and the remote server’s host key is verified automatically using ~/.ssh/known_hosts.

When instantiating the SftpClient class, pass the host, username, and optionally the port (default is 22). To authenticate with a password, use the authPassword function. To authenticate using public key authentication, pass the path along to the private key and the pass string to the authKey function.

package com.sftptogo;

import com.jcraft.jsch.*;
import com.sftptogo.util.Util;

import java.util.Properties;
import java.util.Vector;

/**
 * A simple SFTP client using JSCH http://www.jcraft.com/jsch/
 */
public final class SftpClient {
    private final String      host;
    private final int         port;
    private final String      username;
    private final JSch        jsch;
    private       ChannelSftp channel;
    private       Session     session;

    /**
     * @param host     remote host
     * @param port     remote port
     * @param username remote username
     */
    public SftpClient(String host, int port, String username) {
        this.host     = host;
        this.port     = port;
        this.username = username;
        jsch          = new JSch();
    }

    /**
     * Use default port 22
     *
     * @param host     remote host
     * @param username username on host
     */
    public SftpClient(String host, String username) {
        this(host, 22, username);
    }

    /**
     * Authenticate with remote using password
     *
     * @param password password of remote
     * @throws JSchException If there is problem with credentials or connection
     */
    public void authPassword(String password) throws JSchException {
        session = jsch.getSession(username, host, port);
        //disable known hosts checking
        //if you want to set knows hosts file You can set with jsch.setKnownHosts("path to known hosts file");
        var config = new Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        session.setPassword(password);
        session.connect();
        channel = (ChannelSftp) session.openChannel("sftp");
        channel.connect();
    }


    public void authKey(String keyPath, String pass) throws JSchException {
        jsch.addIdentity(keyPath, pass);
        session = jsch.getSession(username, host, port);
        //disable known hosts checking
        //if you want to set knows hosts file You can set with jsch.setKnownHosts("path to known hosts file");
        var config = new Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        session.connect();
        channel = (ChannelSftp) session.openChannel("sftp");
        channel.connect();
    }
}

Listing Files

Now that we have a working connection, we can use it to list files on the remote SFTP server. Our wrapper function listFiles calls the channel’s ls function to retrieve the list of remote files, iterate over them and print each file’s permissions, name, and size.

/**
 * List all files including directories
 *
 * @param remoteDir Directory on remote from which files will be listed
 * @throws SftpException If there is any problem with listing files related to permissions etc
 * @throws JSchException If there is any problem with connection
 */
@SuppressWarnings("unchecked")
public void listFiles(String remoteDir) throws SftpException, JSchException {
    if (channel == null) {
        throw new IllegalArgumentException("Connection is not available");
    }
    System.out.printf("Listing [%s]...%n", remoteDir);
    channel.cd(remoteDir);
    Vector<ChannelSftp.LsEntry> files = channel.ls(".");
    for (ChannelSftp.LsEntry file : files) {
        var name        = file.getFilename();
        var attrs       = file.getAttrs();
        var permissions = attrs.getPermissionsString();
        var size        = Util.humanReadableByteCount(attrs.getSize());
        if (attrs.isDir()) {
            size = "PRE";
        }
        System.out.printf("[%s] %s(%s)%n", permissions, name, size);
    }
}

Upload File

The next step is to upload a file. Our class’s uploadFile takes two arguments: localPath (the file to upload) and remotePath (where to upload it to on the server). An example call would look like this: client.uploadFile("./local.txt", "/remote.txt");

/**
 * Upload a file to remote
 *
 * @param localPath  full path of location file
 * @param remotePath full path of remote file
 * @throws JSchException If there is any problem with connection
 * @throws SftpException If there is any problem with uploading file permissions etc
 */
public void uploadFile(String localPath, String remotePath) throws JSchException, SftpException {
    System.out.printf("Uploading [%s] to [%s]...%n", localPath, remotePath);
    if (channel == null) {
        throw new IllegalArgumentException("Connection is not available");
    }
    channel.put(localPath, remotePath);
}

Download File

As we finalize the process, we just need to download our files. The downloadFile function also takes two arguments: remotePath (file to download) and localPath (where to download the file to). You would call the function like so: client.downloadFile("/remote.txt", "./download.txt");

/**
 * Download a file from remote
 *
 * @param remotePath full path of remote file
 * @param localPath  full path of where to save file locally
 * @throws SftpException If there is any problem with downloading file related permissions etc
 */
public void downloadFile(String remotePath, String localPath) throws SftpException {
    System.out.printf("Downloading [%s] to [%s]...%n", remotePath, localPath);
    if (channel == null) {
        throw new IllegalArgumentException("Connection is not available");
    }
    channel.get(remotePath, localPath);
}

The Whole Thing

All done! If you would like to run the entire program from start to finish, follow the instructions on how to build and run the project here

package com.sftptogo;

import com.jcraft.jsch.*;
import com.sftptogo.util.Util;

import java.util.Properties;
import java.util.Vector;

/**
 * A simple SFTP client using JSCH http://www.jcraft.com/jsch/
 */
public final class SftpClient {
    private final String      host;
    private final int         port;
    private final String      username;
    private final JSch        jsch;
    private       ChannelSftp channel;
    private       Session     session;

    /**
     * @param host     remote host
     * @param port     remote port
     * @param username remote username
     */
    public SftpClient(String host, int port, String username) {
        this.host     = host;
        this.port     = port;
        this.username = username;
        jsch          = new JSch();
    }

    /**
     * Use default port 22
     *
     * @param host     remote host
     * @param username username on host
     */
    public SftpClient(String host, String username) {
        this(host, 22, username);
    }

    /**
     * Authenticate with remote using password
     *
     * @param password password of remote
     * @throws JSchException If there is problem with credentials or connection
     */
    public void authPassword(String password) throws JSchException {
        session = jsch.getSession(username, host, port);
        //disable known hosts checking
        //if you want to set knows hosts file You can set with jsch.setKnownHosts("path to known hosts file");
        var config = new Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        session.setPassword(password);
        session.connect();
        channel = (ChannelSftp) session.openChannel("sftp");
        channel.connect();
    }


    public void authKey(String keyPath, String pass) throws JSchException {
        jsch.addIdentity(keyPath, pass);
        session = jsch.getSession(username, host, port);
        //disable known hosts checking
        //if you want to set knows hosts file You can set with jsch.setKnownHosts("path to known hosts file");
        var config = new Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        session.connect();
        channel = (ChannelSftp) session.openChannel("sftp");
        channel.connect();
    }

    /**
     * List all files including directories
     *
     * @param remoteDir Directory on remote from which files will be listed
     * @throws SftpException If there is any problem with listing files related to permissions etc
     * @throws JSchException If there is any problem with connection
     */
    @SuppressWarnings("unchecked")
    public void listFiles(String remoteDir) throws SftpException, JSchException {
        if (channel == null) {
            throw new IllegalArgumentException("Connection is not available");
        }
        System.out.printf("Listing [%s]...%n", remoteDir);
        channel.cd(remoteDir);
        Vector<ChannelSftp.LsEntry> files = channel.ls(".");
        for (ChannelSftp.LsEntry file : files) {
            var name        = file.getFilename();
            var attrs       = file.getAttrs();
            var permissions = attrs.getPermissionsString();
            var size        = Util.humanReadableByteCount(attrs.getSize());
            if (attrs.isDir()) {
                size = "PRE";
            }
            System.out.printf("[%s] %s(%s)%n", permissions, name, size);
        }
    }

    /**
     * Upload a file to remote
     *
     * @param localPath  full path of location file
     * @param remotePath full path of remote file
     * @throws JSchException If there is any problem with connection
     * @throws SftpException If there is any problem with uploading file permissions etc
     */
    public void uploadFile(String localPath, String remotePath) throws JSchException, SftpException {
        System.out.printf("Uploading [%s] to [%s]...%n", localPath, remotePath);
        if (channel == null) {
            throw new IllegalArgumentException("Connection is not available");
        }
        channel.put(localPath, remotePath);
    }

    /**
     * Download a file from remote
     *
     * @param remotePath full path of remote file
     * @param localPath  full path of where to save file locally
     * @throws SftpException If there is any problem with downloading file related permissions etc
     */
    public void downloadFile(String remotePath, String localPath) throws SftpException {
        System.out.printf("Downloading [%s] to [%s]...%n", remotePath, localPath);
        if (channel == null) {
            throw new IllegalArgumentException("Connection is not available");
        }
        channel.get(remotePath, localPath);
    }

    /**
     * Delete a file on remote
     *
     * @param remoteFile full path of remote file
     * @throws SftpException If there is any problem with deleting file related to permissions etc
     */
    public void delete(String remoteFile) throws SftpException {
        System.out.printf("Deleting [%s]...%n", remoteFile);
        if (channel == null) {
            throw new IllegalArgumentException("Connection is not available");
        }
        channel.rm(remoteFile);
    }

    /**
     * Disconnect from remote
     */
    public void close() {
        if (channel != null) {
            channel.exit();
        }
        if (session != null && session.isConnected()) {
            session.disconnect();
        }
    }
}

Congratulations on connecting to SFTP using Java!

Cloud FTP with maximum security and reliability
SFTP To Go offers managed cloud storage service - highly available, reliable and secure. Great for companies of any size, any scale.
Try SFTP To Go for free!

Check out more code samples on Github.