Implementing an SFTP Client

In Transferring Files, we covered how to use the high-level API of SshClient to perform basic upload and download of files. To provide a more rich SFTP experience, the Maverick Synergy API provides the SftpClient.

Those familiar with the Maverick Legacy Client API will find the SftpClient similar to the SftpClient class that previously implemented SFTP.

You can use the following template in your application to connect, authenticate and start the SftpClientTask.

try (SshClient ssh = SshClientBuilder.create()
	.withHostname("localhost")
	.withPort(2222)
	.withUsername("root")
	.withPassword("xxxx")
	.build()) {
		
	SftpClient sftp = SftpClientBuilder.create()
		.withClient(ssh)
		.build();
}

Transferring Data

To upload a file from the current file system, you can:

sftp.put("tmp.dmg");

You can also pass OutputStream to receive the file content without going to the local file system.

ByteArrayOutputStream out = new ByteArrayOutputStream();
sftp.get("tmp.dmg", out);

Or get an InputStream of the file content to process.

InputStream in = sftp.getInputStream("tmp.dmg");

Similarly, you can pass an InputStream to write out data from your application held in an InputStream.

InputStream in = ....
sftp.put(in, "tmp.dmg");

Or get an OutputStream to write content to the remote system.

OutputStream out = sftp.getOutputStream("tmp.dmg");

Transferring with Patterns

The methods detailed so far only deal with a single file at a time. For example, we can download all files with a specific pattern using the getFiles method. This returns an array of SftpFile objects that have been transferred.

SftpFile[] files = sftp.getFiles("*rfc*.txt");

We can also do the same and putFiles

sftp.putFiles("*rfc&.txt");

Matching is performed using Glob syntax by default. You can use a Perl Syntax for regular expressions also. To do this you will need to configure the pattern matcher first.

sftp.setRegularExpressionSyntax(SftpClientTask.Perl5Syntax);

Changing Directory

You can change the user’s local directory by calling the following:

sftp.lcd("/tmp");

Or change the remote directory using:

sftp.cd("/opt");

To get the remote working directory

sftp.pwd();

To get the local working directory

sftp.lpwd();

Permissions

There are several methods for manipulating the permissions on the remote file system. Remember that Unix permissions are normally stated in an octal numbering system rather than decimal, so any value passed should be preceded by zero to indicate this to the JVM.

sftp.chmod(PosixPermissionsBuilder.create()
	.fromBitmask(0644)
	.build(), "tmp.dmg");

You can change the owner or group of the file

sftp.chown("501", "tmp.dmg");
sftp.chgrp("501", "tmp.dmg"); 

In SFTP version 3 or below, the UID/GID expected is normally the numerical ID and not the user or group name. Version 4 or above support names. The methods take a string to allow both to be passed. 

By default, a umask is not applied to files and folders created remotely. If you do not want the server to decide the permissions, you should apply a umask setting. You can change the umask value using:

sftp.umask(0022);

This will apply the default permissions of 0666 ^ 0022 for new files and 0777 ^ 0022 for new folders. 

File Attributes 

You can get the current SftpFileAttributes of a file using a stat command.

SftpFileAttributes attrs = sftp.stat("tmp.dmg")

Or the attributes of a link

SftpFileAttributes attrs = sftp.statLink("tmp.dmg")

If you want to change the attributes, get them using the above stat call and make modifications, then call

sftp.setAttributes("tmp.dmg", attrs);

Symbolic Links

To get the target of a symbolic link

sftp.getSymbolicLinkTarget("linkpath");

Moving and Deleting 

To move a file you rename it.

sftp.rename("tmp.dmg", "new.dmg");

To delete a file, use.

sftp.rm("tmp.dmg");