使用JSch在Java中进行文件/目录同步?

时间:2012-02-14 20:04:36

标签: java jsch

是否可以使用JSch在Java中进行文件/目录同步?我需要将目录从远程linux机器同步到我的本地Windows机器。这可能吗?

-Tivakar

2 个答案:

答案 0 :(得分:2)

从SCP服务器下载文件的最简单方法是使用Commons VFS和JSch:

import java.io.*;
import org.apache.commons.io.FileUtils;
import org.apache.commons.vfs2.*;

public class CopyRemoteFile {
    public static void copyRemoteFiles(String host, String user, String remotePath, String localPath) throws IOException {
        FileSystemOptions fsOptions = new FileSystemOptions();
        SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(fsOptions, "no");
        SftpFileSystemConfigBuilder.getInstance().setIdentities(fsOptions,
                new File[] { new File(FileUtils.getUserDirectoryPath() + "/.ssh/id_dsa") });
        DefaultFileSystemManager fsManager = (DefaultFileSystemManager) VFS.getManager();
        String uri = "sftp://" + user + "@" + host + "/" + remotePath;

        FileObject fo = fsManager.resolveFile(uri, fsOptions);

        FileObject[] files = fo.getChildren();
        for (FileObject file : files) {
                    // We will be dealing with the files here only
            if (file.getType() == FileType.FILE) {
                FileUtils.copyInputStreamToFile(file.getContent().getInputStream(),
                        new File(localPath + "/" + file.getName().getBaseName()));
            }
            file.close();
        }

        fo.close();

        fsManager.close();
    }
}

这只是我在Wiki中的一个例子,所以没什么特别的。但请记住,如果您关闭fsManager,您将无法在同一个VM中再次打开它。我在测试此解决方案时遇到了这个问题......

虽然上面的示例没有导入任何JSch类,但无论如何都需要将它放在类路径中。

以上示例使用私钥对远程主机进行身份验证。您可以通过提供密码和修改uri来轻松更改它。

如果您需要同步文件,您可以比较本地文件系统(或数据库或任何其他信息源)和远程文件上的文件日期:

import java.io.*;
import org.apache.commons.io.*;
import org.apache.commons.vfs2.*;
import org.apache.commons.vfs2.impl.*;
import org.apache.commons.vfs2.provider.sftp.*;

public class CopyRemoteFile {
    public static void copyRemoteFiles(final String host, final String user, final String remotePath, final String localPath)
            throws IOException {
        FileSystemOptions fsOptions = new FileSystemOptions();
        SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(fsOptions, "no");
        SftpFileSystemConfigBuilder.getInstance().setIdentities(fsOptions,
                new File[] { new File(FileUtils.getUserDirectoryPath() + "/.ssh/id_dsa") });
        DefaultFileSystemManager fsManager = (DefaultFileSystemManager) VFS.getManager();
        String uri = "sftp://" + user + "@" + host + "/" + remotePath;

        FileObject fo = fsManager.resolveFile(uri, fsOptions);

        FileObject[] files = fo.getChildren();
        for (FileObject file : files) {
            // We will be dealing with the files here only
            File newFile = new File(localPath + "/" + file.getName().getBaseName());
            if (file.getType() == FileType.FILE && newFile.lastModified() != file.getContent().getLastModifiedTime()) {
                FileUtils.copyInputStreamToFile(file.getContent().getInputStream(), newFile);
                newFile.setLastModified(file.getContent().getLastModifiedTime());
            } 
            file.close();
        }

        fo.close();

        fsManager.close();
    }
}

答案 1 :(得分:-1)

请注意:http://the-project.net16.net/Projekte/projekte/Projekte/Programmieren/sftp-synchronisierung.html

有一个完整的程序uploadet。 这是同步部分:

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Vector;

import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.SftpException;

/*
 * This is the heart of the whole Program. I hope, the descriptions are precise enought.
 */
public class Sync{
	public String ServerPath;
	public File LocalFolder;
	public sFTPclient client;
	public ArrayList<String> serverContentList;
	public ArrayList<String> pathList;
		
	public Sync(File local, String to, sFTPclient client){
		this.LocalFolder = local;
		this.ServerPath = to;
		this.client = client;
	}
	
	/*
	 * Executed once. Sets the Server Directory if it exists. 
	 * If the local folder doesn't exist on the Server, it creates it.

	 */
	public void setServerDirectory() throws SftpException{
		try{
			client.sftpChannel.cd(ServerPath);
		}catch(Exception e){
			GUI.addToConsole(ServerPath + " don't exist on your server!");
		}
		
		String serverFolder = ServerPath.substring(ServerPath.lastIndexOf('/')+1, ServerPath.length());
		if(!LocalFolder.getName().equals(serverFolder)){
			try{
				client.sftpChannel.mkdir(LocalFolder.getName());
				client.sftpChannel.cd(LocalFolder.getName());
			} catch (Exception e){
				client.sftpChannel.cd(LocalFolder.getName());
			}
			this.ServerPath = ServerPath + "/" + LocalFolder.getName();
			GUI.setNewServerFolder(ServerPath);
		}
		serverContentList = new ArrayList<String>();
		pathList = new ArrayList<String>();
		
	}
	
	//The contentlist contains all Filenames, that should be synchronized
	public void setToContentList(String ServerFolder) throws SftpException{
		@SuppressWarnings("unchecked")
		Vector<LsEntry> fileList = client.sftpChannel.ls(ServerFolder);
		int size = fileList.size();
		for(int i = 0; i < size; i++){
			if(!fileList.get(i).getFilename().startsWith(".")){
				serverContentList.add(fileList.get(i).getFilename());
				pathList.add(ServerFolder);
			}
		}
	}
	
	/*
	 * Deletes the synchronized elements from the Lists
	 */
	public void deleteFromLists(String name){
		int	position = serverContentList.lastIndexOf(name);
				
		if(position >= 0){	
			serverContentList.remove(position);
			pathList.remove(position);
		}
	}
	
	/*
	 * Main function for synchronizing. Works recursive for local folders.
	 */
	@SuppressWarnings("unchecked")
	public void synchronize(File localFolder, String ServerDir) throws SftpException, FileNotFoundException{
		if(client.sftpChannel.pwd() != ServerDir){
			client.sftpChannel.cd(ServerDir);
		}
		setToContentList(ServerDir);
		
		File[] localList = localFolder.listFiles();
		Vector<LsEntry> ServerList = client.sftpChannel.ls(ServerDir);
		ServerList.remove(0); ServerList.remove(0);
		
		/*
		 * Upload missing Files/Folders
		 */
		int size = localList.length;
		for(int i = 0; i < size; i++){
			if(localList[i].isDirectory()){
				if(checkFolder(localList[i], ServerDir)){
					synchronize(localList[i], ServerDir + "/" + localList[i].getName());
					deleteFromLists("SubFolder");
				}else {
					newFileMaster(true, localList[i], ServerDir);
				}
			} else {
				checkFile(localList[i], ServerDir);
			}
			deleteFromLists(localList[i].getName());
		}
	}
	
	/*
	 * Deletes all files on the server, which are not in the local Folder. Deletes also all missing folders
	 */
	public void deleteRest() throws SftpException, FileNotFoundException{
		int size = serverContentList.size();
		for(int i = 0; i < size; i++){
			client.sftpChannel.cd(pathList.get(i));
			newFileMaster(false, null, serverContentList.get(i));
		}
	}
	
	/*
	 * Copy or delete Files/Folders
	 */
	public void newFileMaster(boolean copyOrNot, File sourcePath, String destPath) throws FileNotFoundException, SftpException{
		FileMaster copy = new FileMaster(copyOrNot, sourcePath, destPath, client.sftpChannel);
		copy.runMaster();
	}
	
	/*
	 *Useful to find errors - Prints out the content-List every time you call the method.
	 *If you have Problems, call it before and after every changes of the serverContentList!
	 */
	/*public void printServerContent(){
		System.out.println("SERVER-Content: " + "\n");
		for(int i = 0; i < serverContentList.size(); i++){
			System.out.println(serverContentList.get(i) + " in " + pathList.get(i));
		}
	}*/
	
	/*
	 * Looks ond the server, if the file is there. If not, or the local file has changed, it copies the file on the server.
	 */
	public void checkFile(File file, String path) throws SftpException, FileNotFoundException{
		client.sftpChannel.cd(path);
		
		if(!serverContentList.contains(file.getName())){
			newFileMaster(true, file, ServerPath);
		} else {
			Long localTimeStamp = file.lastModified();
			Long timeStamp =  client.sftpChannel.stat(file.getName()).getATime()*1000L;

			if(localTimeStamp > timeStamp){
				newFileMaster(false, null, path + "/" + file.getName());
				newFileMaster(true, file, path);
			}
		}
		deleteFromLists(file.getName());
	}
	
	/*
	 * The same as the checkFile function. But it returns a boolean. (Easier to handle in the synchronized funtion)
	 * Don't check, if the folder has changed (I think this can't be the case)
	 */
	public boolean checkFolder(File folder, String path) throws SftpException{
		client.sftpChannel.cd(path);
		if(serverContentList.contains(folder.getName())){
			return true;
		}else { return false; }
	}
	
}