waqas
waqas

Reputation: 1125

Transfer folder and subfolders using ChannelSftp in JSch?

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?

Upvotes: 6

Views: 30115

Answers (3)

Zon
Zon

Reputation: 19880

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).

Upvotes: 14

Lukas K&#228;ppeli
Lukas K&#228;ppeli

Reputation: 11

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());
	}

}

Upvotes: 0

Kalyan Chakravarthi
Kalyan Chakravarthi

Reputation: 319

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);

                    }

                }
            }

         }

Upvotes: 5

Related Questions