File Transfer using SFTP in Java (JSch)
This article shows how to do file transfer from a remote server to the local system and vice versa, using SSH File Transfer Protocol (SFTP) in Java.
P.S Tested with JSch 0.1.55
1. JSch Dependency
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
2. File Transfer – JSch Examples
2.1 In JSch
, we can use put
and get
to do file transfer between servers.
We use put
to transfer files from a local system to the remote server.
channelSftp.put(localFile, remoteFile);
We use get
to download files from a remote server to the local system.
channelSftp.get(remoteFile, localFile);
2.2 Password authentication.
JSch jsch = new JSch();
jsch.setKnownHosts("/home/mkyong/.ssh/known_hosts");
jschSession = jsch.getSession(USERNAME, REMOTE_HOST, REMOTE_PORT);
jschSession.setPassword(PASSWORD);
2.3 Public and private keys authentication, read this Use Public Key Authentication with SSH
- Local private key –
/home/mkyong/.ssh/id_rsa
- Remote public key –
~/.ssh/authorized_keys
JSch jsch = new JSch();
jsch.setKnownHosts("/home/mkyong/.ssh/known_hosts");
jschSession = jsch.getSession(USERNAME, REMOTE_HOST, REMOTE_PORT);
jsch.addIdentity("/home/mkyong/.ssh/id_rsa");
2.4 Review this complete JSch
example to transfer a file from the local system to a remote server 1.2.3.4
, authenticate using an SSH password.
package com.mkyong.io.howto;
import com.jcraft.jsch.*;
public class SFTPFileTransfer {
private static final String REMOTE_HOST = "1.2.3.4";
private static final String USERNAME = "";
private static final String PASSWORD = "";
private static final int REMOTE_PORT = 22;
private static final int SESSION_TIMEOUT = 10000;
private static final int CHANNEL_TIMEOUT = 5000;
public static void main(String[] args) {
String localFile = "/home/mkyong/local/random.txt";
String remoteFile = "/home/mkyong/remote/afile.txt";
Session jschSession = null;
try {
JSch jsch = new JSch();
jsch.setKnownHosts("/home/mkyong/.ssh/known_hosts");
jschSession = jsch.getSession(USERNAME, REMOTE_HOST, REMOTE_PORT);
// authenticate using private key
// jsch.addIdentity("/home/mkyong/.ssh/id_rsa");
// authenticate using password
jschSession.setPassword(PASSWORD);
// 10 seconds session timeout
jschSession.connect(SESSION_TIMEOUT);
Channel sftp = jschSession.openChannel("sftp");
// 5 seconds timeout
sftp.connect(CHANNEL_TIMEOUT);
ChannelSftp channelSftp = (ChannelSftp) sftp;
// transfer file from local to remote server
channelSftp.put(localFile, remoteFile);
// download file from remote server to local
// channelSftp.get(remoteFile, localFile);
channelSftp.exit();
} catch (JSchException | SftpException e) {
e.printStackTrace();
} finally {
if (jschSession != null) {
jschSession.disconnect();
}
}
System.out.println("Done");
}
}
3. JSch Exceptions
Some common exceptions.
3.1 For UnknownHostKey exception, add the remote IP address into the known_hosts
file.
$ ssh-keyscan -t rsa 1.2.3.4 >> ~/.ssh/known_hosts
3.2 For invalid privatekey, convert the private key to another format.
$ ssh-keygen -p -f ~/.ssh/id_rsa -m pem
3.3 For Auth fail
, make sure the provided password is correct.
com.jcraft.jsch.JSchException: Auth fail
at com.jcraft.jsch.Session.connect(Session.java:519)
at com.mkyong.io.howto.SFTPFileTransfer.main(SFTPFileTransfer.java:34)
Download Source Code
$ git clone https://github.com/mkyong/core-java
$ cd java-io
Thanks a lot, it was so useful. And as always you explain very clearly. GOD bless you.
What is timeout needed for 1 GB file transfer
How to change/set remote file permission after transfer in sftp
Thank you so much for this code. It works perfectly.
The code works fine when running locally but throws an Unknownhost exception when running an application inside the Kubernetes POD. I did add a known host locally and point to that file with the method setKnownHosts but it doesn’t work inside the POD (even targetting the known host file).
Do we need to install ssh inside Linux based K8 pod with yum install ssh or JSch is independent of that? If yes, what could be the reason for that?
is it necessary to set a known host
How do we connect if we have the private key as a String value? not in the form of private key file
Hello,
there is any way to limit to use channel.ls but limited to only first 100 files?
Because if i use channel.ls and have hundred of files, these are locked by that script and i cannot run parallel processes to download simultaneously files.
Thanks
I am successful in using JSch sending a file from local to remote directory but need assistance with sending a mainframe data set where the data set name is surrounded by single quotes. I can send a file to a data set without single quote around the name but not with single quotes around the name and I need to use single quotes.
private String datasetName = “‘ABC.DE.FGHI.KL001′”;
getting this error
java.lang.ArrayIndexOutOfBoundsException: 20480
at com.jcraft.jsch.Session.connect(Unknown Source)
at filetransfer.SFTPFileTransfer.main(SFTPFileTransfer.java:34)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
com.jcraft.jsch.JSchException: Session.connect: java.lang.ArrayIndexOutOfBoundsException: 20480
at com.jcraft.jsch.Session.connect(Unknown Source)
at filetransfer.SFTPFileTransfer.main(SFTPFileTransfer.java:34)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Done
created jar and running on local machin
Hi
When I am trying to work with Executor service by creating multiple threads some files are not getting uploaded and I am receiving below error. Can you please help me.
4:
at com.jcraft.jsch.ChannelSftp._realpath(ChannelSftp.java:2362)
at com.jcraft.jsch.ChannelSftp.cd(ChannelSftp.java:342)
at com.test.filesystemservice.CopyFileTask.run(CopyFileTask.java:45)
at com.test.filesystemservice.ParallelTasks.lambda$1(ParallelTasks.java:35)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Did you figure out the root cause &/or solution?
In my case sftp Exception:Algorithm negotiation fail
JSch js = new JSch();
Session s = js.getSession(username, hostname, 22);
s.setPassword(password);
Properties confignn = new Properties();
confignn.put(“StrictHostKeyChecking”, “no”);
s.setConfig(confignn);
s.connect();
Have you solved this? Same error for me 🙁
Good afternoon,
Would I be able to transfer a directory, its subdirectories and all existing files at once?
Zip it and transfer later.
Jsch supports only one file transfer mode – binary. But how does camel sftp support ascii/binary file transfer modes? Camel sftp also internally uses jsch right?
good tutorial
When I give password it works fine, but when I try for SSH public key
like this — jsch.addIdentity(“~/.ssh/authorized_keys”);
Error occurred due to com.jcraft.jsch.JSchException: java.io.FileNotFoundException: C:\Users\****\.ssh\authorized_keys (The system cannot find the file specified)
May I know why its referring to local path instead of remote server
jsch.addIdentity
is used to define your private key, please upload your public key to the remote server.Read this
https://www.linode.com/docs/security/authentication/use-public-key-authentication-with-ssh/