6

I want to transfer a folder and a subfolder using JSch ChannelSftp. I can successfully transfer files using channelsftp.put(src, dest) command but this does not work for folders (at least I could not make it work). So can someone please explain how can I transfer folders and subfolders using ChannelSftp?

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
waqas
  • 1,115
  • 5
  • 19
  • 32

3 Answers3

14

To work with multilevel folder structures in jsch you:

  1. enter them;
  2. list their contents;
  3. do smth with every found item;
  4. repeat 1, 2 & 3 if subfolder is found.

DOWNLOAD dirs method inside your JSCH class:

public void downloadDir(String sourcePath, String destPath) throws SftpException { // With subfolders and all files.
    // Create local folders if absent.
    try {
        new File(destPath).mkdirs();
    } catch (Exception e) {
        System.out.println("Error at : " + destPath);
    }
    sftpChannel.lcd(destPath);

    // Copy remote folders one by one.
    lsFolderCopy(sourcePath, destPath); // Separated because loops itself inside for subfolders.
}

private void lsFolderCopy(String sourcePath, String destPath) throws SftpException { // List source (remote, sftp) directory and create a local copy of it - method for every single directory.
    Vector<ChannelSftp.LsEntry> list = sftpChannel.ls(sourcePath); // List source directory structure.
    for (ChannelSftp.LsEntry oListItem : list) { // Iterate objects in the list to get file/folder names.
        if (!oListItem.getAttrs().isDir()) { // If it is a file (not a directory).
            if (!(new File(destPath + "/" + oListItem.getFilename())).exists() || (oListItem.getAttrs().getMTime() > Long.valueOf(new File(destPath + "/" + oListItem.getFilename()).lastModified() / (long) 1000).intValue())) { // Download only if changed later.
                new File(destPath + "/" + oListItem.getFilename());
                sftpChannel.get(sourcePath + "/" + oListItem.getFilename(), destPath + "/" + oListItem.getFilename()); // Grab file from source ([source filename], [destination filename]).
            }
        } else if (!(".".equals(oListItem.getFilename()) || "..".equals(oListItem.getFilename()))) {
            new File(destPath + "/" + oListItem.getFilename()).mkdirs(); // Empty folder copy.
            lsFolderCopy(sourcePath + "/" + oListItem.getFilename(), destPath + "/" + oListItem.getFilename()); // Enter found folder on server to read its contents and create locally.
        }
    }
}

REMOVE dirs method inside your JSCH class:

try {
    sftpChannel.cd(dir);
    Vector<ChannelSftp.LsEntry> list = sftpChannel.ls(dir); // List source directory structure.
    for (ChannelSftp.LsEntry oListItem : list) { // Iterate objects in the list to get file/folder names.
        if (!oListItem.getAttrs().isDir()) { // If it is a file (not a directory).
            sftpChannel.rm(dir + "/" + oListItem.getFilename()); // Remove file.
        } else if (!(".".equals(oListItem.getFilename()) || "..".equals(oListItem.getFilename()))) { // If it is a subdir.
            try {
                sftpChannel.rmdir(dir + "/" + oListItem.getFilename());  // Try removing subdir.
            } catch (Exception e) { // If subdir is not empty and error occurs.
                lsFolderRemove(dir + "/" + oListItem.getFilename()); // Do lsFolderRemove on this subdir to enter it and clear its contents.
            }
        }
    }
    sftpChannel.rmdir(dir); // Finally remove the required dir.
} catch (SftpException sftpException) {
    System.out.println("Removing " + dir + " failed. It may be already deleted.");
}

CALL these methods from outside like:

MyJSCHClass sftp = new MyJSCHClass();
sftp.removeDir("/mypublic/myfolders");
sftp.disconnect(); // Disconnecting is obligatory - otherwise changes on server can be discarded (e.g. loaded folder disappears).
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Zon
  • 18,610
  • 7
  • 91
  • 99
5

Above code(by zon) works for download as per my understanding.I need to upload to a remote server.I wrote below code to achieve the same.Please try and comment if any issue(it ignores files starting with ".")

private static void lsFolderCopy(String sourcePath, String destPath,
            ChannelSftp sftpChannel) throws SftpException,   FileNotFoundException {
    File localFile = new File(sourcePath);

if(localFile.isFile())
{

    //copy if it is a file
    sftpChannel.cd(destPath);

    if(!localFile.getName().startsWith("."))
    sftpChannel.put(new FileInputStream(localFile), localFile.getName(),ChannelSftp.OVERWRITE);
}   
else{
    System.out.println("inside else "+localFile.getName());
    File[] files = localFile.listFiles();

    if(files!=null && files.length > 0 && !localFile.getName().startsWith("."))
    {

        sftpChannel.cd(destPath);
        SftpATTRS  attrs = null;

    //check if the directory is already existing
    try {
        attrs = sftpChannel.stat(destPath+"/"+localFile.getName());
    } catch (Exception e) {
        System.out.println(destPath+"/"+localFile.getName()+" not found");
    }

    //else create a directory   
    if (attrs != null) {
        System.out.println("Directory exists IsDir="+attrs.isDir());
    } else {
        System.out.println("Creating dir "+localFile.getName());
        sftpChannel.mkdir(localFile.getName());
    }

    //System.out.println("length " + files.length);

     for(int i =0;i<files.length;i++) 
        {

         lsFolderCopy(files[i].getAbsolutePath(),destPath+"/"+localFile.getName(),sftpChannel);

                    }

                }
            }

         }
  • JSCH is for remote connection. To work with local filesystem you would ruther utilise java.io.File class. But you can try connecting your localhost as if it were a remote one as well. – Zon Sep 29 '15 at 14:09
  • Zon.. this code I posted is was to upload to a remote system... (This code was used to upload a ear file from developer box to server box- sort of automatically using jenkins..) – Kalyan Chakravarthi Nov 05 '15 at 04:31
  • This is excellent code and working fine. but what if i want to copy files starting with dot(.) as well. After commenting that line, Still its not copying the same? – Aditya Apr 30 '17 at 07:29
  • Yes it should.. try commenting this line out : if(!localFile.getName().startsWith(".")) – Kalyan Chakravarthi May 01 '17 at 08:07
0

From: http://the-project.net16.net/Projekte/projekte/Projekte/Programmieren/sftp-synchronisierung.html

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Vector;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.SftpException;

public class FileMaster {
 public boolean FileAction;
 public File local;
 public String serverDir;
 public ChannelSftp channel;
 
 public FileMaster(boolean copyOrDelete, File local, String to, ChannelSftp channel){
  this.FileAction = copyOrDelete;
  this.local = local;
  this.serverDir = to;
  this.channel = channel;
 }
 
 /*
  * If FileAction = true, the File local is copied to the serverDir, else the file is deleted.
  */
 public void runMaster() throws FileNotFoundException, SftpException{
  if(FileAction){
   copy(local, serverDir, channel);
  } else { 
   delete(serverDir, channel);
  }
 }
 
 /*
  * Copies recursive
  */
 public static void copy(File localFile, String destPath, ChannelSftp clientChannel) throws SftpException, FileNotFoundException{
  if(localFile.isDirectory()){
   clientChannel.mkdir(localFile.getName());
   GUI.addToConsole("Created Folder: " + localFile.getName() + " in " + destPath);

   destPath = destPath + "/" + localFile.getName();
   clientChannel.cd(destPath);
   
   for(File file: localFile.listFiles()){
    copy(file, destPath, clientChannel);
   }
   clientChannel.cd(destPath.substring(0, destPath.lastIndexOf('/')));
  } else {
   GUI.addToConsole("Copying File: " + localFile.getName() + " to " + destPath);
   clientChannel.put(new FileInputStream(localFile), localFile.getName(),ChannelSftp.OVERWRITE);
  }

 }
 
 /*
  * File/Folder is deleted, but not recursive
  */
 public void delete(String filename, ChannelSftp sFTPchannel) throws SftpException{  
  if(sFTPchannel.stat(filename).isDir()){
   @SuppressWarnings("unchecked")
   Vector<LsEntry> fileList = sFTPchannel.ls(filename);
   sFTPchannel.cd(filename);
   int size = fileList.size();
   for(int i = 0; i < size; i++){
    if(!fileList.get(i).getFilename().startsWith(".")){
     delete(fileList.get(i).getFilename(), sFTPchannel);
    }
   }
   sFTPchannel.cd("..");
   sFTPchannel.rmdir(filename);
  } else {
   sFTPchannel.rm(filename.toString());
  }
  GUI.addToConsole("Deleted: " + filename + " in " + sFTPchannel.pwd());
 }

}