使用JSch的Java文件/目录同步?

Is it possible to do file/directory sync in Java using JSch ? I need to sync directory from a remote linux machine to my local windows machine. Is this possible ?

-Tivakar

#0

The easiest way to download files from SCP server is using Commons VFS along with 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();
    }
}

It's just an example I got in my Wiki, so nothing fancy. But do keep in mind that if you'll close fsManager, you will not be able to open it again in the same VM. I got this issue while testing this solution...

Although the example above does not import any JSch classes, you need to put it in the classpath anyway.

The above example is using private key to authenticate with the remote host. You can easily change that by providing password and modifying the uri to include that.

If you need to sync files, you can compare dates of the files on the local file system (or DB, or any other source of the information) and the remote files:

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

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

There is a whole Programm uploadet. Here is the sync Part:

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

推荐文章

Android MediaPlayer WakeLock不工作

Android MediaPlayer WakeLock不工作

推荐文章

使用ActiveSupport将utc转换为ruby对象

使用ActiveSupport将utc转换为ruby对象

推荐文章

获取无法批量分配受保护的属性:地址

获取无法批量分配受保护的属性:地址

推荐文章

代码点火器-控制器和方法

代码点火器-控制器和方法

推荐文章

Python:从有序列表中删除不在无序列表中的条目

Python:从有序列表中删除不在无序列表中的条目

推荐文章

Silverlight Listbox ItemTemplate用户控件绑定

Silverlight Listbox ItemTemplate用户控件绑定

推荐文章

主干网.js-使用输入中的值筛选集合

主干网.js-使用输入中的值筛选集合

推荐文章

Android文本视图动画,一次一个单词

Android文本视图动画,一次一个单词

推荐文章

给出奇怪结果的trapz函数

给出奇怪结果的trapz函数

推荐文章

带缩放功能的UIScrollView在缩放之前不会滚动

带缩放功能的UIScrollView在缩放之前不会滚动

推荐文章

选择div中的最后一个元素

选择div中的最后一个元素

推荐文章

多个类的Efficent函数替换

多个类的Efficent函数替换

推荐文章

CKEditor原始数据到控制器

CKEditor原始数据到控制器

推荐文章

如何使标签来回滚动一个单词?

如何使标签来回滚动一个单词?

推荐文章

如果键是字符串而不是整数,我如何创建一个循环来打印数组中的所有元素?

如果键是字符串而不是整数,我如何创建一个循环来打印数组中的所有元素?

推荐文章

Java驱动程序类错误

Java驱动程序类错误