I was tempted to use my old code when I decide to look around for something cleaner just to come across this great post about sftp using Apache VFS. I made few changes to be able to sftp any input stream as a file to a remote SFTP site which I am sharing below.
Dependencies:
org.apache.commons commons-vfs2 2.0 com.jcraft jsch 0.1.45
The upload:
package com.nestorurquiza.utils; package com.nestorurquiza.utils; import java.io.InputStream; import java.io.OutputStream; import org.apache.commons.io.IOUtils; 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; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * All credits for http://www.memorylack.com/2011/06/apache-commons-vfs-for-sftp.html * * nestoru - 2012/01/24: Small changes: * 1. Using logging instead of System.out.println() * 2. The initial directory is not the user home directory * 3. No additional slashes when adding remoteFilePath. * 4. Using InputStream instead of path to a local file * * If you need extra functionality check out the url above * * * */ public class SftpUtils { private final static Logger log = LoggerFactory.getLogger(SftpUtils.class); public static void upload(String hostName, String username, String password, InputStream localInputStream, String localInputStreamName, String remoteFilePath) { StandardFileSystemManager manager = new StandardFileSystemManager(); FileObject localFile; FileObject remoteFile; try { manager.init(); FileSystemOptions fileSystemOptions = createDefaultOptions(); // Create local file object //FileObject localFile = manager.resolveFile(f.getAbsolutePath()); localFile = manager.resolveFile("ram://path/needed/" + localInputStreamName); localFile.createFile(); OutputStream localOutputStream = localFile.getContent().getOutputStream(); IOUtils.copy(localInputStream, localOutputStream); localOutputStream.flush(); // Create remote file object remoteFile = manager.resolveFile( createConnectionString(hostName, username, password, remoteFilePath), fileSystemOptions); // Copy local file to sftp server remoteFile.copyFrom(localFile, Selectors.SELECT_SELF); log.debug("File upload success"); } catch (Exception e) { throw new RuntimeException(e); } finally { remoteFile != null ? remoteFile.close(); localFile != null ? localFile.close(); manager.close(); } } public static String createConnectionString(String hostName, String username, String password, String remoteFilePath) { // result: "sftp://user:123456@domainname.com/resume.pdf return "sftp://" + username + ":" + password + "@" + hostName + remoteFilePath; } public static FileSystemOptions createDefaultOptions() throws FileSystemException { // Create SFTP options FileSystemOptions opts = new FileSystemOptions(); // SSH Key checking SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking( opts, "no"); // Root directory set to user home SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, false); // Timeout is count by Milliseconds SftpFileSystemConfigBuilder.getInstance().setTimeout(opts, 10000); return opts; } }
Then a quick unit test that I comment out Just because I am not interested really in regression test but rather just testing if the method works as expected (I do not like main() methods inside the classes)
package com.nestorurquiza.utils; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import org.junit.Test; import org.xml.sax.SAXException; public class SftpUtilsTest { //@Ignore @Test public void uploadTest() throws IOException, Exception, SAXException { String hostName = "bhubint.nestorurquiza.com"; String userame = "user"; String password = "pass"; String localFilePath = "/tmp/test.txt"; String remoteFilePath = "/home/report/report/test.txt"; //SftpUtils.upload(hostName, userame, password, localFilePath, remoteFilePath); File f = new File(localFilePath); if (!f.exists()) throw new RuntimeException("Error. Local file not found"); FileInputStream fileInputStream = new FileInputStream(f); SftpUtils.upload(hostName, userame, password, fileInputStream, "test.txt", remoteFilePath); } }
4 comments:
I think we must close and delete localFile after coppying
Do we need to close and and delete localFile?
Nhật Quang Phan Thanks. You are correct. In fact the removeFile needs to be closed as well. Just added both lines.
Post a Comment