21

I need a pure Apache Commons VFS solution/code/example for

  1. Uploading a local file to Remote Host Location
  2. Check if a File exists in Remote Host Location
  3. Downloading a Remote Host File to Local file location
  4. Move a file from one Remote Location to another in the same Host
  5. Delete a file from the Remote Host Location

via SFTP calls.

The solution should only use Apache Commons VFS api and shouldn't refer to the underlying JSCH library.

Ashok Goli
  • 5,043
  • 8
  • 38
  • 68
  • Please note that Spring has an Integration library for FTP transfers - https://github.com/spring-projects/spring-integration-samples/tree/master/basic/ftp – Ashok Goli Mar 10 '16 at 09:08

1 Answers1

49

The below SFTP Utility gives an example of Upload, Exist, Download, Move and Delete operations. I have used this in several of my projects. The below code uses api calls from Apache Commons VFS library only.

Please make sure that you put the following JAR's in your project's build path:

  • commons-logging-1.1.3.jar
  • commons-vfs2-2.0.jar
  • hamcrest-core-1.3.jar
  • jsch-0.1.50.jar

Any other compatible versions would do as well.

import java.io.File;

import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
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;

/**
 * The class SFTPUtil containing uploading, downloading, checking if file exists
 * and deleting functionality using Apache Commons VFS (Virtual File System)
 * Library
 * 
 * @author Ashok
 * 
 */
public class SFTPUtility {

    public static void main(String[] args) {
        String hostName = "PutYourHostNameHere";
        String username = "PutYourUserNameForHostHere";
        String password = "PutYourPasswordForHostHere";

        String localFilePath = "C:\\FakePath\\FakeFile.txt";
        String remoteFilePath = "/FakeRemotePath/FakeRemoteFile.txt";       
        String remoteTempFilePath = "/FakeRemoteTempPath/FakeRemoteTempFile.txt";

        upload(hostName, username, password, localFilePath, remoteFilePath);
        exist(hostName, username, password, remoteFilePath);
        download(hostName, username, password, localFilePath,remoteFilePath);
        move(hostName, username, password, remoteFilePath, remoteTempFilePath);
        delete(hostName, username, password, remoteFilePath);
    }

    /**
     * Method to upload a file in Remote server
     * 
     * @param hostName
     *            HostName of the server
     * @param username
     *            UserName to login
     * @param password
     *            Password to login
     * @param localFilePath
     *            LocalFilePath. Should contain the entire local file path -
     *            Directory and Filename with \\ as separator
     * @param remoteFilePath
     *            remoteFilePath. Should contain the entire remote file path -
     *            Directory and Filename with / as separator
     */
    public static void upload(String hostName, String username, String password, String localFilePath, String remoteFilePath) {

        File file = new File(localFilePath);
        if (!file.exists())
            throw new RuntimeException("Error. Local file not found");

        StandardFileSystemManager manager = new StandardFileSystemManager();

        try {
            manager.init();

            // Create local file object
            FileObject localFile = manager.resolveFile(file.getAbsolutePath());

            // Create remote file object
            FileObject remoteFile = manager.resolveFile(createConnectionString(hostName, username, password, remoteFilePath), createDefaultOptions());
            /*
             * use createDefaultOptions() in place of fsOptions for all default
             * options - Ashok.
             */

            // Copy local file to sftp server
            remoteFile.copyFrom(localFile, Selectors.SELECT_SELF);

            System.out.println("File upload success");
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            manager.close();
        }
    }

    public static boolean move(String hostName, String username, String password, String remoteSrcFilePath, String remoteDestFilePath){
        StandardFileSystemManager manager = new StandardFileSystemManager();

        try {
            manager.init();

            // Create remote object
            FileObject remoteFile = manager.resolveFile(createConnectionString(hostName, username, password, remoteSrcFilePath), createDefaultOptions());
            FileObject remoteDestFile = manager.resolveFile(createConnectionString(hostName, username, password, remoteDestFilePath), createDefaultOptions());

            if (remoteFile.exists()) {
                remoteFile.moveTo(remoteDestFile);;
                System.out.println("Move remote file success");
                return true;
            }
            else{
                System.out.println("Source file doesn't exist");
                return false;
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            manager.close();
        }
    }

    /**
     * Method to download the file from remote server location
     * 
     * @param hostName
     *            HostName of the server
     * @param username
     *            UserName to login
     * @param password
     *            Password to login
     * @param localFilePath
     *            LocalFilePath. Should contain the entire local file path -
     *            Directory and Filename with \\ as separator
     * @param remoteFilePath
     *            remoteFilePath. Should contain the entire remote file path -
     *            Directory and Filename with / as separator
     */
    public static void download(String hostName, String username, String password, String localFilePath, String remoteFilePath) {

        StandardFileSystemManager manager = new StandardFileSystemManager();

        try {
            manager.init();

            // Append _downlaod_from_sftp to the given file name.
            //String downloadFilePath = localFilePath.substring(0, localFilePath.lastIndexOf(".")) + "_downlaod_from_sftp" + localFilePath.substring(localFilePath.lastIndexOf("."), localFilePath.length());

            // Create local file object. Change location if necessary for new downloadFilePath
            FileObject localFile = manager.resolveFile(localFilePath);

            // Create remote file object
            FileObject remoteFile = manager.resolveFile(createConnectionString(hostName, username, password, remoteFilePath), createDefaultOptions());

            // Copy local file to sftp server
            localFile.copyFrom(remoteFile, Selectors.SELECT_SELF);

            System.out.println("File download success");
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            manager.close();
        }
    }

    /**
     * Method to delete the specified file from the remote system
     * 
     * @param hostName
     *            HostName of the server
     * @param username
     *            UserName to login
     * @param password
     *            Password to login
     * @param localFilePath
     *            LocalFilePath. Should contain the entire local file path -
     *            Directory and Filename with \\ as separator
     * @param remoteFilePath
     *            remoteFilePath. Should contain the entire remote file path -
     *            Directory and Filename with / as separator
     */
    public static void delete(String hostName, String username, String password, String remoteFilePath) {
        StandardFileSystemManager manager = new StandardFileSystemManager();

        try {
            manager.init();

            // Create remote object
            FileObject remoteFile = manager.resolveFile(createConnectionString(hostName, username, password, remoteFilePath), createDefaultOptions());

            if (remoteFile.exists()) {
                remoteFile.delete();
                System.out.println("Delete remote file success");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            manager.close();
        }
    }

    // Check remote file is exist function:
    /**
     * Method to check if the remote file exists in the specified remote
     * location
     * 
     * @param hostName
     *            HostName of the server
     * @param username
     *            UserName to login
     * @param password
     *            Password to login
     * @param remoteFilePath
     *            remoteFilePath. Should contain the entire remote file path -
     *            Directory and Filename with / as separator
     * @return Returns if the file exists in the specified remote location
     */
    public static boolean exist(String hostName, String username, String password, String remoteFilePath) {
        StandardFileSystemManager manager = new StandardFileSystemManager();

        try {
            manager.init();

            // Create remote object
            FileObject remoteFile = manager.resolveFile(createConnectionString(hostName, username, password, remoteFilePath), createDefaultOptions());

            System.out.println("File exist: " + remoteFile.exists());

            return remoteFile.exists();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            manager.close();
        }
    }

    /**
     * Generates SFTP URL connection String
     * 
     * @param hostName
     *            HostName of the server
     * @param username
     *            UserName to login
     * @param password
     *            Password to login
     * @param remoteFilePath
     *            remoteFilePath. Should contain the entire remote file path -
     *            Directory and Filename with / as separator
     * @return concatenated SFTP URL string
     */
    public static String createConnectionString(String hostName, String username, String password, String remoteFilePath) {
        return "sftp://" + username + ":" + password + "@" + hostName + "/" + remoteFilePath;
    }

    /**
     * Method to setup default SFTP config
     * 
     * @return the FileSystemOptions object containing the specified
     *         configuration options
     * @throws FileSystemException
     */
    public static FileSystemOptions createDefaultOptions() throws FileSystemException {
        // Create SFTP options
        FileSystemOptions opts = new FileSystemOptions();

        // SSH Key checking
        SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(opts, "no");

        /*
         * Using the following line will cause VFS to choose File System's Root
         * as VFS's root. If I wanted to use User's home as VFS's root then set
         * 2nd method parameter to "true"
         */
        // Root directory set to user home
        SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, false);

        // Timeout is count by Milliseconds
        SftpFileSystemConfigBuilder.getInstance().setTimeout(opts, 10000);

        return opts;
    }
}
Ashok Goli
  • 5,043
  • 8
  • 38
  • 68
  • Why the following jar are needed hamcrest-core-1.3.jar jsch-0.1.50.jar – Senthil Muthiah Jul 24 '14 at 14:26
  • Because VFS has a dependency on JSCH and hamcrest. VFS internally uses JSCH but provides a cleaner and controlled API – Ashok Goli Jul 24 '14 at 14:53
  • @Ashok, your code is clear but I got an authentication issue, I'm sure I'musing the right user/pssd, and I tested the sftp to my remote server using terminal and it works, but when using running your example, I got: cannot connect to the server, com.jcraft.jsch.JSchException: USERAUTH fail, serAuthPublicKey.java:119) – Salim R Apr 30 '15 at 15:23
  • @Salim A Are there any SSL Certificates in between your servers? Can't say more without looking at your code :) – Ashok Goli May 06 '15 at 13:37
  • @Ashok there was a problem with my SSH user , I tried another user and the upload works normally from my PC to the server. thank you – Salim R May 07 '15 at 14:13
  • @AshokFelix Hi ashok am also using the code but am getting error shown below Exception in thread "main" java.lang.RuntimeException: org.apache.commons.vfs2.FileSystemException: Invalid absolute URI "sftp://abc12:***@148.171.37//axphome/abc12/important.txt". at SFTPUtility.upload(SFTPUtility.java:70) at SFTPUtility.main(SFTPUtility.java:21) – Anand Kumar May 12 '16 at 13:46
  • @AnandKumar - The URI you constructed might not be correct. It should be `sftp://abc12:***@148.171.37/axphome/abc12/important.txt`. Also have a look @ http://stackoverflow.com/questions/29539422/expecting-to-follow-the-hostname-in-uri-exception-when-password-contains – Ashok Goli May 12 '16 at 13:52
  • org.apache.commons.vfs2.impl.StandardFileSystemManager info INFO: Using "C:\Users\abc\AppData\Local\Temp\vfs_cache" as temporary files store. Exception in thread "main" java.lang.RuntimeException: org.apache.commons.vfs2.FileSystemException: Invalid absolute URI "sftp://akuma12:***@148.171.92.37/axphome/akuma12/1.txt". at SFTPUtility.upload(SFTPUtility.java:70) at SFTPUtility.main(SFTPUtility.java:21) Caused by: org.apache.commons.vfs2.FileSystemException: Invalid absolute URI "sftp://akuma12:***@148.171.92.37/axphome/akuma12/1.txt". – Anand Kumar May 12 '16 at 13:57
  • my whole error shown above even I corrected the URI – Anand Kumar May 12 '16 at 13:58
  • @AnandKumar - Will need the FULL stack trace. Check the following: 1. Port Number 2. Permissions of the User on the FTP server 3. JAR dependencies - especially JSCH jar version. Make sure you have compatible and stable versions in your classpath. – Ashok Goli May 12 '16 at 14:04
  • am using jsch-0.1.42 is that any problem and here where you using port number. You didn't use port here. – Anand Kumar May 12 '16 at 14:12
  • @AnandKumar - Try using the latest version - preferably > v0.1.50 – Ashok Goli May 12 '16 at 14:15
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/111774/discussion-between-anand-kumar-and-ashok-felix). – Anand Kumar May 12 '16 at 14:15
  • @AshokFelix i used your code for ftp and it works fine, but for sftp im still getting connection problem Caused by: org.apache.commons.vfs2.FileSystemException: Could not connect to SFTP server ... Caused by: com.jcraft.jsch.JSchException: failed to send channel request at com.jcraft.jsch.Request.write(Request.java:65) at com.jcraft.jsch.RequestSftp.request(RequestSftp.java:47) – user405458 Jul 05 '16 at 15:34
  • 1
    @user405458 This is not an issue in the code above. Please check if the SFTP server is started. Refer: http://stackoverflow.com/questions/14769164/jsch-error-failed-to-send-channel-request – Ashok Goli Jul 05 '16 at 15:37
  • @AshokFelix the server is started and i can download files using FileZilla client – user405458 Jul 05 '16 at 15:52
  • @AshokFelix as you suggested the problem was with the ftp server i tried a demo server and everything works fine :) But i can't understand why it is possible to connect using FileZilla – user405458 Jul 05 '16 at 16:17
  • Glad it worked out. Must be some server level configurations. – Ashok Goli Jul 05 '16 at 16:18
  • @ Ashok. Great example. Can you please say me how to close session / connection properly. is manager.close(); enough? – deadend Jul 21 '17 at 13:22
  • 1
    @DEADEND `manager.close();` should be enough for the above example – Ashok Goli Jul 26 '17 at 20:05
  • @AshokGoli I am getting java.lang.NullPointerException: Cannot invoke "java.nio.file.attribute.BasicFileAttributes.lastModifiedTime()" because "this.attrs" is null while calling manager.init() any idea on this? Thanks! – Bosco Apr 11 '22 at 04:47
  • I posted question here https://stackoverflow.com/questions/71822831/standardfilesystemmanager-init-npe-error-java-lang-nullpointerexception-cannot – Bosco Apr 11 '22 at 05:41