2012-02-14 88 views
1

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

-Tivakar

+0

你能更详细解释这项任务?同步programaticaly或您只是寻找一个应用程序的解决方案?同步是什么意思? – 2012-02-14 20:15:35

+0

同步是同步。我想以编程方式做。我在我的linux机器上有一个目录,我想下载/同步目录中的文件到本地的Windows机器上。我想以编程方式执行此操作,因为我有一个名为“sync”的按钮,应该启动此过程。 – Tivakar 2012-02-14 20:43:41

+0

对于我来说_sync_意味着我想从远程主机下载所有新的和修改的文件,并从本地目录上传新的和修改的文件。但那是我。无论如何 - 你有你的答案:) – 2012-02-14 22:06:01

回答

2

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

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,则无法在同一个虚拟机中再次打开它。我在测试这个解决方案时遇到了这个问题...

尽管上面的例子没有导入任何JSch类,但是您仍然需要将它放在classpath中。

上述示例使用私钥对远程主机进行身份验证。您可以通过提供密码并修改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(); 
    } 
} 
+0

感谢Lukasz的代码。完全正确,同步“我想从远程主机下载所有新的和修改的文件,并从本地目录上传新的和修改的文件”。下面的代码将所有文件从远程复制到本地,即使该文件未被修改。我不想下载未修改的文件。我该如何实现这个目标? – Tivakar 2012-02-15 21:49:03

+1

请 - 请阅读API。它在那里。 'File.getContent()。getLastModifiedTime()'会给你所需要的信息。因此,比较这两者可以为您提供文件是否被修改的信息。你可以用本地文件,数据库的某个源或者存储......来检查它。只需路径,名称和最后修改时间即可。 – 2012-02-15 22:34:27

+0

感谢卢卡斯。真的很有帮助 – Tivakar 2012-02-16 04:49:38

-1

看:

如果需要同步文件,你可以在本地文件系统(或DB,或信息的任何其他来源)和远程文件上比较文件的日期在:http://the-project.net16.net/Projekte/projekte/Projekte/Programmieren/sftp-synchronisierung.html

有一个完整的Programm 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{ 
 
\t public String ServerPath; 
 
\t public File LocalFolder; 
 
\t public sFTPclient client; 
 
\t public ArrayList<String> serverContentList; 
 
\t public ArrayList<String> pathList; 
 
\t \t 
 
\t public Sync(File local, String to, sFTPclient client){ 
 
\t \t this.LocalFolder = local; 
 
\t \t this.ServerPath = to; 
 
\t \t this.client = client; 
 
\t } 
 
\t 
 
\t /* 
 
\t * Executed once. Sets the Server Directory if it exists. 
 
\t * If the local folder doesn't exist on the Server, it creates it. 
 

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

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