How to retrieve a file from a server via SFTP?
Asked Answered
E

16

243

I'm trying to retrieve a file from a server using SFTP (as opposed to FTPS) using Java. How can I do this?

Excitement answered 18/8, 2008 at 13:43 Comment(0)
D
209

Another option is to consider looking at the JSch library. JSch seems to be the preferred library for a few large open source projects, including Eclipse, Ant and Apache Commons HttpClient, amongst others.

It supports both user/pass and certificate-based logins nicely, as well as all a whole host of other yummy SSH2 features.

Here's a simple remote file retrieve over SFTP. Error handling is left as an exercise for the reader :-)

JSch jsch = new JSch();

String knownHostsFilename = "/home/username/.ssh/known_hosts";
jsch.setKnownHosts( knownHostsFilename );

Session session = jsch.getSession( "remote-username", "remote-host" );    
{
  // "interactive" version
  // can selectively update specified known_hosts file 
  // need to implement UserInfo interface
  // MyUserInfo is a swing implementation provided in 
  //  examples/Sftp.java in the JSch dist
  UserInfo ui = new MyUserInfo();
  session.setUserInfo(ui);

  // OR non-interactive version. Relies in host key being in known-hosts file
  session.setPassword( "remote-password" );
}

session.connect();

Channel channel = session.openChannel( "sftp" );
channel.connect();

ChannelSftp sftpChannel = (ChannelSftp) channel;

sftpChannel.get("remote-file", "local-file" );
// OR
InputStream in = sftpChannel.get( "remote-file" );
  // process inputstream as needed

sftpChannel.exit();
session.disconnect();
Dogear answered 19/8, 2008 at 9:44 Comment(7)
Cheekysoft, I noticed - while using Jsch - removing files on the sftp-server does not work. Also renaming files does not work too. Any ideas please??? AndyCastera
Sorry, it is not something i work with at the moment. (Please try and leave these sort of responses as comments -- like this message -- and not as a new answer to the original question)Dogear
What is that code block after the assignment of session? Is that some fancy Java syntax I've never seen? If so - what does it accomplish being written that way?Shroud
@p1x3l5 standard java syntax allows a block to be inserted anywhere; it can be used to provide finer control over variable scope, if you wish. However, in this case, it is just a visual aid to help indicate the two implementation choices: either use the interactive version which requests a password from the user, or use a hardcoded password requiring no user intervention but arguably an additional security risk.Dogear
Another example relying on JSch library : baeldung.com/java-file-sftpStradivari
@RaymondChenon Be aware that this example on Baeldung does not appear to close the session after the transfer which could cause issues on the server side. You would probably want to call channelSftp.getSession().disconnect() after channelSftp.exit().Jacelynjacenta
JSch hasn't been updated since 2018. Is this still the best answer in 2023?Falbala
H
118

Here is the complete source code of an example using JSch without having to worry about the ssh key checking.

import com.jcraft.jsch.*;

public class TestJSch {
    public static void main(String args[]) {
        JSch jsch = new JSch();
        Session session = null;
        try {
            session = jsch.getSession("username", "127.0.0.1", 22);
            session.setConfig("StrictHostKeyChecking", "no");
            session.setPassword("password");
            session.connect();

            Channel channel = session.openChannel("sftp");
            channel.connect();
            ChannelSftp sftpChannel = (ChannelSftp) channel;
            sftpChannel.get("remotefile.txt", "localfile.txt");
            sftpChannel.exit();
            session.disconnect();
        } catch (JSchException e) {
            e.printStackTrace();  
        } catch (SftpException e) {
            e.printStackTrace();
        }
    }
}
Hyperbolism answered 22/4, 2010 at 12:51 Comment(4)
A finally block should be used to include the channel clean-up code, to ensure that it always runs.Myocardiograph
I'm getting this exception now: com.jcraft.jsch.JSchException: Session.connect: java.security.InvalidAlgorithmParameterException: Prime size must be multiple of 64, and can only range from 512 to 2048 (inclusive)Frankie
I found JSCH to have 0 or 1 extra dependencies. You can ignore the JZLIB dependency if you disable compression. // disable compression session.setConfig("compression.s2c", "none"); session.setConfig("compression.c2s", "none");Nixon
Without strict host checking you're susceptible to a man-in-the-middle attack.Subtemperate
I
48

Below is an example using Apache Common VFS:

FileSystemOptions fsOptions = new FileSystemOptions();
SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(fsOptions, "no");
FileSystemManager fsManager = VFS.getManager();
String uri = "sftp://user:password@host:port/absolute-path";
FileObject fo = fsManager.resolveFile(uri, fsOptions);
Ignominious answered 30/3, 2010 at 20:46 Comment(3)
Another nice thing to do is to set the timeout, so that if the remote system is offline, you don't hang there forever. You can do this just like was done for the host key check disable: SftpFileSystemConfigBuilder.getInstance().setTimeout(fsOptions, 5000);Pinwork
How would you advise close this connection when using multiple SFTP clients at the same time ?Unfair
What if my password contains @ symbol?Carvey
P
25

There is a nice comparison of the 3 mature Java libraries for SFTP: Commons VFS, SSHJ and JSch

To sum up SSHJ has the clearest API and it's the best out of them if you don't need other storages support provided by Commons VFS.

Here is edited SSHJ example from github:

final SSHClient ssh = new SSHClient();
ssh.loadKnownHosts(); // or, to skip host verification: ssh.addHostKeyVerifier(new PromiscuousVerifier())
ssh.connect("localhost");
try {
    ssh.authPassword("user", "password"); // or ssh.authPublickey(System.getProperty("user.name"))
    final SFTPClient sftp = ssh.newSFTPClient();
    try {
        sftp.get("test_file", "/tmp/test.tmp");
    } finally {
        sftp.close();
    }
} finally {
    ssh.disconnect();
}
Purington answered 5/4, 2016 at 9:52 Comment(2)
Is there a way to get the file as an InputStream?Sudor
sshj in 2019 is still well maintained and is used by Alpakka (Akka) projectExtender
V
24

A nice abstraction on top of Jsch is Apache commons-vfs which offers a virtual filesystem API that makes accessing and writing SFTP files almost transparent. Worked well for us.

Viburnum answered 19/8, 2008 at 20:12 Comment(4)
is it possible to use pre-shared keys in combination with commons-vfs?Cossack
Yes it is. If you need non-standard identities you can call SftpFileSystemConfigBuilder.getInstance().setIdentities(...).Demosthenes
You can use pre-shared keys. But this keys have to be without password. OtrosLogViewer is using SSH key authorization with VFS but requires to remove passphrase from key (code.google.com/p/otroslogviewer/wiki/SftpAuthPubKey)Sword
I must say, that library is reallt overhead for the question requirements. the part that handles sftp is something like 10% of the library or even less...Kendakendal
E
23

This was the solution I came up with http://sourceforge.net/projects/sshtools/ (most error handling omitted for clarity). This is an excerpt from my blog

SshClient ssh = new SshClient();
ssh.connect(host, port);
//Authenticate
PasswordAuthenticationClient passwordAuthenticationClient = new PasswordAuthenticationClient();
passwordAuthenticationClient.setUsername(userName);
passwordAuthenticationClient.setPassword(password);
int result = ssh.authenticate(passwordAuthenticationClient);
if(result != AuthenticationProtocolState.COMPLETE){
     throw new SFTPException("Login to " + host + ":" + port + " " + userName + "/" + password + " failed");
}
//Open the SFTP channel
SftpClient client = ssh.openSftpClient();
//Send the file
client.put(filePath);
//disconnect
client.quit();
ssh.disconnect();
Excitement answered 18/8, 2008 at 13:49 Comment(1)
I agree (belatedly), it worked fine for the original site/download I required but it refuesed to work for the new one. I'm in the process of switching to JSchExcitement
G
13

See http://www.mysamplecode.com/2013/06/sftp-apache-commons-file-download.html

Apache Commons SFTP library

Common java properties file for all the examples

serverAddress=111.222.333.444

userId=myUserId

password=myPassword

remoteDirectory=products/

localDirectory=import/

Upload file to remote server using SFTP

import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;
 
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.Selectors;
import org.apache.commons.vfs2.impl.StandardFileSystemManager;
import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;
 
public class SendMyFiles {
 
 static Properties props;
 
 public static void main(String[] args) {
 
  SendMyFiles sendMyFiles = new SendMyFiles();
  if (args.length < 1)
  {
   System.err.println("Usage: java " + sendMyFiles.getClass().getName()+
     " Properties_file File_To_FTP ");
   System.exit(1);
  }
 
  String propertiesFile = args[0].trim();
  String fileToFTP = args[1].trim();
  sendMyFiles.startFTP(propertiesFile, fileToFTP);
 
 }
 
 public boolean startFTP(String propertiesFilename, String fileToFTP){
 
  props = new Properties();
  StandardFileSystemManager manager = new StandardFileSystemManager();
 
  try {
 
   props.load(new FileInputStream("properties/" + propertiesFilename));
   String serverAddress = props.getProperty("serverAddress").trim();
   String userId = props.getProperty("userId").trim();
   String password = props.getProperty("password").trim();
   String remoteDirectory = props.getProperty("remoteDirectory").trim();
   String localDirectory = props.getProperty("localDirectory").trim();
 
   //check if the file exists
   String filepath = localDirectory +  fileToFTP;
   File file = new File(filepath);
   if (!file.exists())
    throw new RuntimeException("Error. Local file not found");
 
   //Initializes the file manager
   manager.init();
    
   //Setup our SFTP configuration
   FileSystemOptions opts = new FileSystemOptions();
   SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(
     opts, "no");
   SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, true);
   SftpFileSystemConfigBuilder.getInstance().setTimeout(opts, 10000);
    
   //Create the SFTP URI using the host name, userid, password,  remote path and file name
   String sftpUri = "sftp://" + userId + ":" + password +  "@" + serverAddress + "/" + 
     remoteDirectory + fileToFTP;
    
   // Create local file object
   FileObject localFile = manager.resolveFile(file.getAbsolutePath());
 
   // Create remote file object
   FileObject remoteFile = manager.resolveFile(sftpUri, opts);
 
   // Copy local file to sftp server
   remoteFile.copyFrom(localFile, Selectors.SELECT_SELF);
   System.out.println("File upload successful");
 
  }
  catch (Exception ex) {
   ex.printStackTrace();
   return false;
  }
  finally {
   manager.close();
  }
 
  return true;
 }
 
  
}

Download file from remote server using SFTP

import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;
 
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.Selectors;
import org.apache.commons.vfs2.impl.StandardFileSystemManager;
import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;
 
public class GetMyFiles {
 
 static Properties props;
 
 public static void main(String[] args) {
 
  GetMyFiles getMyFiles = new GetMyFiles();
  if (args.length < 1)
  {
   System.err.println("Usage: java " + getMyFiles.getClass().getName()+
   " Properties_filename File_To_Download ");
   System.exit(1);
  }
 
  String propertiesFilename = args[0].trim();
  String fileToDownload = args[1].trim();
  getMyFiles.startFTP(propertiesFilename, fileToDownload);
    
 }
 
 public boolean startFTP(String propertiesFilename, String fileToDownload){
 
  props = new Properties();
  StandardFileSystemManager manager = new StandardFileSystemManager();
 
  try {
 
   props.load(new FileInputStream("properties/" + propertiesFilename));
   String serverAddress = props.getProperty("serverAddress").trim();
   String userId = props.getProperty("userId").trim();
   String password = props.getProperty("password").trim();
   String remoteDirectory = props.getProperty("remoteDirectory").trim();
   String localDirectory = props.getProperty("localDirectory").trim();
 
    
   //Initializes the file manager
   manager.init();
    
   //Setup our SFTP configuration
   FileSystemOptions opts = new FileSystemOptions();
   SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(
     opts, "no");
   SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, true);
   SftpFileSystemConfigBuilder.getInstance().setTimeout(opts, 10000);
    
   //Create the SFTP URI using the host name, userid, password,  remote path and file name
   String sftpUri = "sftp://" + userId + ":" + password +  "@" + serverAddress + "/" + 
     remoteDirectory + fileToDownload;
    
   // Create local file object
   String filepath = localDirectory +  fileToDownload;
   File file = new File(filepath);
   FileObject localFile = manager.resolveFile(file.getAbsolutePath());
 
   // Create remote file object
   FileObject remoteFile = manager.resolveFile(sftpUri, opts);
 
   // Copy local file to sftp server
   localFile.copyFrom(remoteFile, Selectors.SELECT_SELF);
   System.out.println("File download successful");
 
  }
  catch (Exception ex) {
   ex.printStackTrace();
   return false;
  }
  finally {
   manager.close();
  }
 
  return true;
 }
 
}

Delete a file on remote server using SFTP

import java.io.FileInputStream;
import java.util.Properties;
 
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.impl.StandardFileSystemManager;
import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;
 
public class DeleteRemoteFile {
 
 static Properties props;
 
 public static void main(String[] args) {
 
  DeleteRemoteFile getMyFiles = new DeleteRemoteFile();
  if (args.length < 1)
  {
   System.err.println("Usage: java " + getMyFiles.getClass().getName()+
   " Properties_filename File_To_Delete ");
   System.exit(1);
  }
 
  String propertiesFilename = args[0].trim();
  String fileToDownload = args[1].trim();
  getMyFiles.startFTP(propertiesFilename, fileToDownload);
    
 }
 
 public boolean startFTP(String propertiesFilename, String fileToDownload){
 
  props = new Properties();
  StandardFileSystemManager manager = new StandardFileSystemManager();
 
  try {
 
   props.load(new FileInputStream("properties/" + propertiesFilename));
   String serverAddress = props.getProperty("serverAddress").trim();
   String userId = props.getProperty("userId").trim();
   String password = props.getProperty("password").trim();
   String remoteDirectory = props.getProperty("remoteDirectory").trim();
    
    
   //Initializes the file manager
   manager.init();
    
   //Setup our SFTP configuration
   FileSystemOptions opts = new FileSystemOptions();
   SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(
     opts, "no");
   SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, true);
   SftpFileSystemConfigBuilder.getInstance().setTimeout(opts, 10000);
    
   //Create the SFTP URI using the host name, userid, password,  remote path and file name
   String sftpUri = "sftp://" + userId + ":" + password +  "@" + serverAddress + "/" + 
     remoteDirectory + fileToDownload;
    
   //Create remote file object
   FileObject remoteFile = manager.resolveFile(sftpUri, opts);
 
   //Check if the file exists
   if(remoteFile.exists()){
    remoteFile.delete();
    System.out.println("File delete successful");
   }
   
  }
  catch (Exception ex) {
   ex.printStackTrace();
   return false;
  }
  finally {
   manager.close();
  }
 
  return true;
 }
 
}
Garotte answered 24/9, 2013 at 7:51 Comment(1)
how to configure while having ssh-key (public key) to copy files on server. Because i need to make ssh_trust between my server and remote server.Dihedral
F
8

hierynomus/sshj has a complete implementation of SFTP version 3 (what OpenSSH implements)

Example code from SFTPUpload.java

package net.schmizz.sshj.examples;

import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.sftp.SFTPClient;
import net.schmizz.sshj.xfer.FileSystemFile;

import java.io.File;
import java.io.IOException;

/** This example demonstrates uploading of a file over SFTP to the SSH server. */
public class SFTPUpload {

    public static void main(String[] args)
            throws IOException {
        final SSHClient ssh = new SSHClient();
        ssh.loadKnownHosts();
        ssh.connect("localhost");
        try {
            ssh.authPublickey(System.getProperty("user.name"));
            final String src = System.getProperty("user.home") + File.separator + "test_file";
            final SFTPClient sftp = ssh.newSFTPClient();
            try {
                sftp.put(new FileSystemFile(src), "/tmp");
            } finally {
                sftp.close();
            }
        } finally {
            ssh.disconnect();
        }
    }

}
Fyke answered 8/3, 2010 at 21:12 Comment(1)
nice job!! an example in the main page could be helpful though.Freeze
M
6

JSch library is the powerful library that can be used to read file from SFTP server. Below is the tested code to read file from SFTP location line by line

JSch jsch = new JSch();
        Session session = null;
        try {
            session = jsch.getSession("user", "127.0.0.1", 22);
            session.setConfig("StrictHostKeyChecking", "no");
            session.setPassword("password");
            session.connect();

            Channel channel = session.openChannel("sftp");
            channel.connect();
            ChannelSftp sftpChannel = (ChannelSftp) channel;

            InputStream stream = sftpChannel.get("/usr/home/testfile.txt");
            try {
                BufferedReader br = new BufferedReader(new InputStreamReader(stream));
                String line;
                while ((line = br.readLine()) != null) {
                    System.out.println(line);
                }

            } catch (IOException io) {
                System.out.println("Exception occurred during reading file from SFTP server due to " + io.getMessage());
                io.getMessage();

            } catch (Exception e) {
                System.out.println("Exception occurred during reading file from SFTP server due to " + e.getMessage());
                e.getMessage();

            }

            sftpChannel.exit();
            session.disconnect();
        } catch (JSchException e) {
            e.printStackTrace();
        } catch (SftpException e) {
            e.printStackTrace();
        }

Please refer the blog for whole program.

Magneto answered 4/10, 2017 at 7:59 Comment(0)
E
3

Andy, to delete file on remote system you need to use (channelExec) of JSch and pass unix/linux commands to delete it.

Ethology answered 8/3, 2011 at 7:54 Comment(0)
I
2

Try edtFTPj/PRO, a mature, robust SFTP client library that supports connection pools and asynchronous operations. Also supports FTP and FTPS so all bases for secure file transfer are covered.

Irvinirvine answered 27/5, 2009 at 10:32 Comment(0)
P
2

I found complete working example for SFTP in java using JSCH API http://kodehelp.com/java-program-for-uploading-file-to-sftp-server/

Paraph answered 18/1, 2011 at 20:34 Comment(0)
E
2

Though answers above were very helpful, I've spent a day to make them work, facing various exceptions like "broken channel", "rsa key unknown" and "packet corrupt".

Below is a working reusable class for SFTP FILES UPLOAD/DOWNLOAD using JSch library.

Upload usage:

SFTPFileCopy upload = new SFTPFileCopy(true, /path/to/sourcefile.png", /path/to/destinationfile.png");

Download usage:

SFTPFileCopy download = new SFTPFileCopy(false, "/path/to/sourcefile.png", "/path/to/destinationfile.png");

The class code:

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UIKeyboardInteractive;
import com.jcraft.jsch.UserInfo;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.swing.JOptionPane;
import menue.Menue;

public class SFTPFileCopy1 {

    public SFTPFileCopy1(boolean upload, String sourcePath, String destPath) throws FileNotFoundException, IOException {
        Session session = null;
        Channel channel = null;
        ChannelSftp sftpChannel = null;
        try {
            JSch jsch = new JSch();
            //jsch.setKnownHosts("/home/user/.putty/sshhostkeys");
            session = jsch.getSession("login", "mysite.com", 22);
            session.setPassword("password");

            UserInfo ui = new MyUserInfo() {
                public void showMessage(String message) {

                    JOptionPane.showMessageDialog(null, message);

                }

                public boolean promptYesNo(String message) {

                    Object[] options = {"yes", "no"};

                    int foo = JOptionPane.showOptionDialog(null,
                            message,
                            "Warning",
                            JOptionPane.DEFAULT_OPTION,
                            JOptionPane.WARNING_MESSAGE,
                            null, options, options[0]);

                    return foo == 0;

                }
            };
            session.setUserInfo(ui);

            session.setConfig("StrictHostKeyChecking", "no");
            session.connect();
            channel = session.openChannel("sftp");
            channel.setInputStream(System.in);
            channel.setOutputStream(System.out);
            channel.connect();
            sftpChannel = (ChannelSftp) channel;

            if (upload) { // File upload.
                byte[] bufr = new byte[(int) new File(sourcePath).length()];
                FileInputStream fis = new FileInputStream(new File(sourcePath));
                fis.read(bufr);
                ByteArrayInputStream fileStream = new ByteArrayInputStream(bufr);
                sftpChannel.put(fileStream, destPath);
                fileStream.close();
            } else { // File download.
                byte[] buffer = new byte[1024];
                BufferedInputStream bis = new BufferedInputStream(sftpChannel.get(sourcePath));
                OutputStream os = new FileOutputStream(new File(destPath));
                BufferedOutputStream bos = new BufferedOutputStream(os);
                int readCount;
                while ((readCount = bis.read(buffer)) > 0) {
                    bos.write(buffer, 0, readCount);
                }
                bis.close();
                bos.close();
            }
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            if (sftpChannel != null) {
                sftpChannel.exit();
            }
            if (channel != null) {
                channel.disconnect();
            }
            if (session != null) {
                session.disconnect();
            }
        }
    }

    public static abstract class MyUserInfo
            implements UserInfo, UIKeyboardInteractive {

        public String getPassword() {
            return null;
        }

        public boolean promptYesNo(String str) {
            return false;
        }

        public String getPassphrase() {
            return null;
        }

        public boolean promptPassphrase(String message) {
            return false;
        }

        public boolean promptPassword(String message) {
            return false;
        }

        public void showMessage(String message) {
        }

        public String[] promptKeyboardInteractive(String destination,
                String name,
                String instruction,
                String[] prompt,
                boolean[] echo) {

            return null;
        }
    }
}
Ergo answered 1/8, 2013 at 22:28 Comment(0)
A
1

You also have JFileUpload with SFTP add-on (Java too): http://www.jfileupload.com/products/sftp/index.html

Annul answered 14/2, 2009 at 11:38 Comment(1)
JFileUpload is an applet, not a lib. License is commercial. Doesn't look active, either.Aftonag
N
1

I use this SFTP API called Zehon, it's great, so easy to use with a lot of sample code. Here is the site http://www.zehon.com

Norway answered 18/6, 2009 at 8:10 Comment(1)
Zehon seems dead. And where's the source? What 'license' is behind 'free'?Aftonag
D
0

The best solution I've found is Paramiko. There's a Java version.

Duggins answered 11/1, 2009 at 15:2 Comment(1)
github.com/terencehonles/jaramiko is abandoned in favor of JSch (see notice on github).Aftonag

© 2022 - 2024 — McMap. All rights reserved.