2012-02-14 2 views
1

Возможно ли выполнить синхронизацию файлов/каталогов на Java с помощью JSch? Мне нужно синхронизировать каталог с удаленной Linux-машины на моем локальном компьютере Windows. Это возможно ?Синхронизация файлов/каталогов на Java с использованием JSch?

-Tivakar

+0

Можете ли вы объяснить эту задачу более подробно? Синхронизация программно или вы просто ищете решение для приложения? Что вы понимаете под синхронизацией? –

+0

Синхронизация - синхронизация. Я хотел сделать это программно. У меня есть каталог в моей Linux-машине, и я хотел загрузить/синхронизировать файлы в каталоге на свою локальную машину Windows. Я хотел сделать это программно, так как у меня есть кнопка с именем «sync», которая должна инициировать этот процесс. – Tivakar

+0

Для меня _sync_ означает, что я хочу загрузить все новые и измененные файлы с удаленного хоста и загрузить новые и измененные файлы из локального каталога. Но это я. В любом случае - вы получили свой ответ :) –

ответ

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

Это просто пример, который я получил в моей вики, так что ничего фантазии. Но имейте в виду, что если вы закроете fsManager, вы не сможете открыть его снова в той же виртуальной машине. Я получил эту проблему при тестировании этого решения ...

Хотя приведенный выше пример не импортирует классы 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(); 
    } 
} 
+0

Спасибо Lukasz за код. Правильно, для синхронизации «Я хочу загрузить все новые и измененные файлы с удаленного хоста и загрузить новые и измененные файлы из локального каталога». Приведенный ниже код копирует все файлы с удаленного на локальный, даже если файл не изменяется. Я не хочу загружать файл, который не изменяется. Как я могу добиться этого? – Tivakar

+1

Пожалуйста, пожалуйста - прочитайте API. Это все. 'File.getContent(). GetLastModifiedTime()' предоставит вам необходимую информацию. Поэтому сравнение этих двух может предоставить вам информацию о том, был ли файл изменен или нет. И вы можете проверить это с локальным файлом, некоторым источником базы данных или хранить ... что угодно. Просто путь, имя и последнее измененное время - это то, что вам нужно. –

+0

Спасибо Lukasz.Действительно полезно – Tivakar

-1

Look по адресу: http://the-project.net16.net/Projekte/projekte/Projekte/Programmieren/sftp-synchronisierung.html

Существует целая загрузка программы. Вот часть синхронизации:

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 
 
}

Смежные вопросы