Як отримати файл із сервера через SFTP?


228

Я намагаюся отримати файл із сервера за допомогою SFTP (на відміну від FTPS) за допомогою Java. Як я можу це зробити?

Відповіді:


198

Ще один варіант - розглянути можливість перегляду бібліотеки JSch . Здається, JSch є кращою бібліотекою для кількох великих проектів з відкритим кодом, серед яких Eclipse, Ant та Apache Commons HttpClient.

Він чудово підтримує як користувач / пропуск, так і сертифікати на основі сертифікатів, а також цілий ряд інших смачних SSH2 функцій.

Ось просте віддалене завантаження файлів через SFTP. Поводження з помилками залишається читачем як вправа :-)

JSch jsch = new JSch();

String knownHostsFilename = "/home/username/.ssh/known_hosts";
jsch.setKnownHosts( knownHostsFilename );

Session session = jsch.getSession( "remote-username", "remote-host" );    
{
  // "interactive" version
  // can selectively update specified known_hosts file 
  // need to implement UserInfo interface
  // MyUserInfo is a swing implementation provided in 
  //  examples/Sftp.java in the JSch dist
  UserInfo ui = new MyUserInfo();
  session.setUserInfo(ui);

  // OR non-interactive version. Relies in host key being in known-hosts file
  session.setPassword( "remote-password" );
}

session.connect();

Channel channel = session.openChannel( "sftp" );
channel.connect();

ChannelSftp sftpChannel = (ChannelSftp) channel;

sftpChannel.get("remote-file", "local-file" );
// OR
InputStream in = sftpChannel.get( "remote-file" );
  // process inputstream as needed

sftpChannel.exit();
session.disconnect();

1
Cheekysoft, я помітив - при використанні Jsch - видалення файлів на sftp-сервері не працює. Також перейменування файлів теж не працює. Будь-які ідеї, будь ласка ??? Andy

1
На жаль, наразі це не те, з чим я працюю. (Будь ласка, спробуйте залишити такі відповіді як коментарі - як це повідомлення - а не як нову відповідь на початкове запитання)
Cheekysoft

1
Що це за кодовий блок після призначення сеансу? Це якийсь химерний синтаксис Java, якого я ніколи не бачив? Якщо так - що це означає, щоб писати саме так?
Майкл Петерсон

3
@ p1x3l5 стандартний синтаксис java дозволяє вставити блок де завгодно; за його допомогою можна забезпечити більш точний контроль над змінною областю. Однак у цьому випадку це лише наочна допомога, яка допоможе вказати два варіанти реалізації: або використовувати інтерактивну версію, яка запитує пароль від користувача, або використовувати жорсткий код, який не вимагає втручання користувача, але, мабуть, додатковий ризик для безпеки.
Cheekysoft

109

Ось повний вихідний код прикладу, що використовує JSch, не турбуючись про перевірку ключа ssh.

import com.jcraft.jsch.*;

public class TestJSch {
    public static void main(String args[]) {
        JSch jsch = new JSch();
        Session session = null;
        try {
            session = jsch.getSession("username", "127.0.0.1", 22);
            session.setConfig("StrictHostKeyChecking", "no");
            session.setPassword("password");
            session.connect();

            Channel channel = session.openChannel("sftp");
            channel.connect();
            ChannelSftp sftpChannel = (ChannelSftp) channel;
            sftpChannel.get("remotefile.txt", "localfile.txt");
            sftpChannel.exit();
            session.disconnect();
        } catch (JSchException e) {
            e.printStackTrace();  
        } catch (SftpException e) {
            e.printStackTrace();
        }
    }
}

15
Для finallyвключення коду очищення каналу слід використовувати блок для забезпечення його виконання.
hotshot309

Зараз я отримую цей виняток: com.jcraft.jsch.JSchException: Session.connect: java.security.InvalidAlgorithmParameterException: Prime size must be multiple of 64, and can only range from 512 to 2048 (inclusive)
anon58192932

Я виявив, що JSCH має 0 або 1 додаткових залежностей. Якщо ви відключите стиснення, ви можете ігнорувати залежність JZLIB. // відключити компресію session.setConfig ("compression.s2c", "none"); session.setConfig ("compression.c2s", "none");
englebart

1
Без суворої перевірки хазяїна ви сприйнятливі до атаки "середній чоловік".
rustyx

44

Нижче наводиться приклад використання Apache Common VFS:

FileSystemOptions fsOptions = new FileSystemOptions();
SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(fsOptions, "no");
FileSystemManager fsManager = VFS.getManager();
String uri = "sftp://user:password@host:port/absolute-path";
FileObject fo = fsManager.resolveFile(uri, fsOptions);

5
Ще одна приємна річ - це встановити тайм-аут, так що якщо віддалена система в автономному режимі, ви не зависаєте там назавжди. Ви можете зробити це так, як це було зроблено для відключення перевірки ключа хоста: SftpFileSystemConfigBuilder.getInstance (). SetTimeout (fsOptions, 5000);
Скотт Джонс

Як би ви порадили закрити це з'єднання, коли одночасно користуєтесь кількома клієнтами SFTP?
2Big2BeSmall

2
Що робити, якщо мій пароль містить символ @?
Користувач3

23

Це було рішення, до якого я придумав http://sourceforge.net/projects/sshtools/ (більшість поводження з помилками опущені для наочності). Це уривок з мого блогу

SshClient ssh = new SshClient();
ssh.connect(host, port);
//Authenticate
PasswordAuthenticationClient passwordAuthenticationClient = new PasswordAuthenticationClient();
passwordAuthenticationClient.setUsername(userName);
passwordAuthenticationClient.setPassword(password);
int result = ssh.authenticate(passwordAuthenticationClient);
if(result != AuthenticationProtocolState.COMPLETE){
     throw new SFTPException("Login to " + host + ":" + port + " " + userName + "/" + password + " failed");
}
//Open the SFTP channel
SftpClient client = ssh.openSftpClient();
//Send the file
client.put(filePath);
//disconnect
client.quit();
ssh.disconnect();

7
Я згоден (запізніло), він спрацював чудово для початкового сайту / завантаження, яке мені потрібно, але він відмовився працювати над новим. Я переходжу на JSch
David Hayes

23

Приємна абстракція на вершині Jsch - Apache commons-vfs, яка пропонує API віртуальної файлової системи, що робить доступ та запис SFTP-файлів майже прозорими. Добре працювали для нас.


1
чи можна використовувати загальнодоступні ключі в поєднанні з commons-vfs?
Бенедікт Вальдвогель

2
Так. Якщо вам потрібні нестандартні ідентичності, ви можете зателефонувати на SftpFileSystemConfigBuilder.getInstance (). SetIdentities (...).
Russ Hayward

Можна використовувати загальнодоступні клавіші. Але ці ключі повинні бути без пароля. OtrosLogViewer використовує авторизацію ключа SSH з VFS, але вимагає видалити пароль із ключа ( code.google.com/p/otroslogviewer/wiki/SftpAuthPubKey )
KrzyH

19

Існує приємне порівняння трьох зрілих бібліотек Java для SFTP: Commons VFS, SSHJ та JSch

Підводячи підсумки, SSHJ має найясніший API, і це найкраще з них, якщо вам не потрібна інша підтримка зберігання даних, надана Commons VFS.

Ось відредагований приклад SSHJ від github :

final SSHClient ssh = new SSHClient();
ssh.loadKnownHosts(); // or, to skip host verification: ssh.addHostKeyVerifier(new PromiscuousVerifier())
ssh.connect("localhost");
try {
    ssh.authPassword("user", "password"); // or ssh.authPublickey(System.getProperty("user.name"))
    final SFTPClient sftp = ssh.newSFTPClient();
    try {
        sftp.get("test_file", "/tmp/test.tmp");
    } finally {
        sftp.close();
    }
} finally {
    ssh.disconnect();
}

2
Чи є спосіб отримати файл у вигляді InputStream?
Йоган

2
sshj у 2019 році все ще доглядається і використовується проектом Alpakka (Akka)
Maxence

13

Бібліотека SFTP Apache Commons

Загальний файл властивостей Java для всіх прикладів

serverAddress = 111.222.333.444

userId = myUserId

пароль = myPassword

remoteDirectory = товари /

localDirectory = імпорт /

Завантажте файл на віддалений сервер за допомогою SFTP

import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;

import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.Selectors;
import org.apache.commons.vfs2.impl.StandardFileSystemManager;
import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;

public class SendMyFiles {

 static Properties props;

 public static void main(String[] args) {

  SendMyFiles sendMyFiles = new SendMyFiles();
  if (args.length < 1)
  {
   System.err.println("Usage: java " + sendMyFiles.getClass().getName()+
     " Properties_file File_To_FTP ");
   System.exit(1);
  }

  String propertiesFile = args[0].trim();
  String fileToFTP = args[1].trim();
  sendMyFiles.startFTP(propertiesFile, fileToFTP);

 }

 public boolean startFTP(String propertiesFilename, String fileToFTP){

  props = new Properties();
  StandardFileSystemManager manager = new StandardFileSystemManager();

  try {

   props.load(new FileInputStream("properties/" + propertiesFilename));
   String serverAddress = props.getProperty("serverAddress").trim();
   String userId = props.getProperty("userId").trim();
   String password = props.getProperty("password").trim();
   String remoteDirectory = props.getProperty("remoteDirectory").trim();
   String localDirectory = props.getProperty("localDirectory").trim();

   //check if the file exists
   String filepath = localDirectory +  fileToFTP;
   File file = new File(filepath);
   if (!file.exists())
    throw new RuntimeException("Error. Local file not found");

   //Initializes the file manager
   manager.init();

   //Setup our SFTP configuration
   FileSystemOptions opts = new FileSystemOptions();
   SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(
     opts, "no");
   SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, true);
   SftpFileSystemConfigBuilder.getInstance().setTimeout(opts, 10000);

   //Create the SFTP URI using the host name, userid, password,  remote path and file name
   String sftpUri = "sftp://" + userId + ":" + password +  "@" + serverAddress + "/" + 
     remoteDirectory + fileToFTP;

   // Create local file object
   FileObject localFile = manager.resolveFile(file.getAbsolutePath());

   // Create remote file object
   FileObject remoteFile = manager.resolveFile(sftpUri, opts);

   // Copy local file to sftp server
   remoteFile.copyFrom(localFile, Selectors.SELECT_SELF);
   System.out.println("File upload successful");

  }
  catch (Exception ex) {
   ex.printStackTrace();
   return false;
  }
  finally {
   manager.close();
  }

  return true;
 }


}

Завантажте файл з віддаленого сервера за допомогою SFTP

import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;

import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.Selectors;
import org.apache.commons.vfs2.impl.StandardFileSystemManager;
import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;

public class GetMyFiles {

 static Properties props;

 public static void main(String[] args) {

  GetMyFiles getMyFiles = new GetMyFiles();
  if (args.length < 1)
  {
   System.err.println("Usage: java " + getMyFiles.getClass().getName()+
   " Properties_filename File_To_Download ");
   System.exit(1);
  }

  String propertiesFilename = args[0].trim();
  String fileToDownload = args[1].trim();
  getMyFiles.startFTP(propertiesFilename, fileToDownload);

 }

 public boolean startFTP(String propertiesFilename, String fileToDownload){

  props = new Properties();
  StandardFileSystemManager manager = new StandardFileSystemManager();

  try {

   props.load(new FileInputStream("properties/" + propertiesFilename));
   String serverAddress = props.getProperty("serverAddress").trim();
   String userId = props.getProperty("userId").trim();
   String password = props.getProperty("password").trim();
   String remoteDirectory = props.getProperty("remoteDirectory").trim();
   String localDirectory = props.getProperty("localDirectory").trim();


   //Initializes the file manager
   manager.init();

   //Setup our SFTP configuration
   FileSystemOptions opts = new FileSystemOptions();
   SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(
     opts, "no");
   SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, true);
   SftpFileSystemConfigBuilder.getInstance().setTimeout(opts, 10000);

   //Create the SFTP URI using the host name, userid, password,  remote path and file name
   String sftpUri = "sftp://" + userId + ":" + password +  "@" + serverAddress + "/" + 
     remoteDirectory + fileToDownload;

   // Create local file object
   String filepath = localDirectory +  fileToDownload;
   File file = new File(filepath);
   FileObject localFile = manager.resolveFile(file.getAbsolutePath());

   // Create remote file object
   FileObject remoteFile = manager.resolveFile(sftpUri, opts);

   // Copy local file to sftp server
   localFile.copyFrom(remoteFile, Selectors.SELECT_SELF);
   System.out.println("File download successful");

  }
  catch (Exception ex) {
   ex.printStackTrace();
   return false;
  }
  finally {
   manager.close();
  }

  return true;
 }

}

Видаліть файл на віддаленому сервері за допомогою SFTP

import java.io.FileInputStream;
import java.util.Properties;

import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.impl.StandardFileSystemManager;
import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;

public class DeleteRemoteFile {

 static Properties props;

 public static void main(String[] args) {

  DeleteRemoteFile getMyFiles = new DeleteRemoteFile();
  if (args.length < 1)
  {
   System.err.println("Usage: java " + getMyFiles.getClass().getName()+
   " Properties_filename File_To_Delete ");
   System.exit(1);
  }

  String propertiesFilename = args[0].trim();
  String fileToDownload = args[1].trim();
  getMyFiles.startFTP(propertiesFilename, fileToDownload);

 }

 public boolean startFTP(String propertiesFilename, String fileToDownload){

  props = new Properties();
  StandardFileSystemManager manager = new StandardFileSystemManager();

  try {

   props.load(new FileInputStream("properties/" + propertiesFilename));
   String serverAddress = props.getProperty("serverAddress").trim();
   String userId = props.getProperty("userId").trim();
   String password = props.getProperty("password").trim();
   String remoteDirectory = props.getProperty("remoteDirectory").trim();


   //Initializes the file manager
   manager.init();

   //Setup our SFTP configuration
   FileSystemOptions opts = new FileSystemOptions();
   SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(
     opts, "no");
   SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, true);
   SftpFileSystemConfigBuilder.getInstance().setTimeout(opts, 10000);

   //Create the SFTP URI using the host name, userid, password,  remote path and file name
   String sftpUri = "sftp://" + userId + ":" + password +  "@" + serverAddress + "/" + 
     remoteDirectory + fileToDownload;

   //Create remote file object
   FileObject remoteFile = manager.resolveFile(sftpUri, opts);

   //Check if the file exists
   if(remoteFile.exists()){
    remoteFile.delete();
    System.out.println("File delete successful");
   }

  }
  catch (Exception ex) {
   ex.printStackTrace();
   return false;
  }
  finally {
   manager.close();
  }

  return true;
 }

}


як налаштувати при наявності ssh-ключ (відкритий ключ) для копіювання файлів на сервер. Тому що мені потрібно зробити ssh_trust між моїм сервером та віддаленим сервером.
MS Parmar

7

hierynomus / sshj має повну реалізацію версії 3 SFTP (що реалізує OpenSSH)

Приклад коду з SFTPUpload.java

package net.schmizz.sshj.examples;

import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.sftp.SFTPClient;
import net.schmizz.sshj.xfer.FileSystemFile;

import java.io.File;
import java.io.IOException;

/** This example demonstrates uploading of a file over SFTP to the SSH server. */
public class SFTPUpload {

    public static void main(String[] args)
            throws IOException {
        final SSHClient ssh = new SSHClient();
        ssh.loadKnownHosts();
        ssh.connect("localhost");
        try {
            ssh.authPublickey(System.getProperty("user.name"));
            final String src = System.getProperty("user.home") + File.separator + "test_file";
            final SFTPClient sftp = ssh.newSFTPClient();
            try {
                sftp.put(new FileSystemFile(src), "/tmp");
            } finally {
                sftp.close();
            }
        } finally {
            ssh.disconnect();
        }
    }

}

2
хороша робота!! приклад на головній сторінці може бути корисним.
OhadR

4

Бібліотека JSch - це потужна бібліотека, яка може бути використана для читання файлів з SFTP-сервера. Нижче наводиться перевірений код для читання файлу з розташування SFTP рядок за рядком

JSch jsch = new JSch();
        Session session = null;
        try {
            session = jsch.getSession("user", "127.0.0.1", 22);
            session.setConfig("StrictHostKeyChecking", "no");
            session.setPassword("password");
            session.connect();

            Channel channel = session.openChannel("sftp");
            channel.connect();
            ChannelSftp sftpChannel = (ChannelSftp) channel;

            InputStream stream = sftpChannel.get("/usr/home/testfile.txt");
            try {
                BufferedReader br = new BufferedReader(new InputStreamReader(stream));
                String line;
                while ((line = br.readLine()) != null) {
                    System.out.println(line);
                }

            } catch (IOException io) {
                System.out.println("Exception occurred during reading file from SFTP server due to " + io.getMessage());
                io.getMessage();

            } catch (Exception e) {
                System.out.println("Exception occurred during reading file from SFTP server due to " + e.getMessage());
                e.getMessage();

            }

            sftpChannel.exit();
            session.disconnect();
        } catch (JSchException e) {
            e.printStackTrace();
        } catch (SftpException e) {
            e.printStackTrace();
        }

Будь ласка, перегляньте блог для всієї програми.


3

Енді, для видалення файлу на віддаленій системі вам потрібно використовувати (channelExec)JSch і передавати команди Unix / linux, щоб видалити його.


2

Спробуйте edtFTPj / PRO , зрілу, надійну бібліотеку клієнтів SFTP, яка підтримує пули підключення та асинхронні операції. Також підтримує FTP та FTPS, тому всі бази для безпечної передачі файлів охоплені.



2

Хоча відповіді вище були дуже корисними, я витратив день, щоб змусити їх працювати, зіткнувшись з різними винятками, такими як "зламаний канал", "ключ rsa невідомий" та "корумпований пакет".

Нижче представлений робочий клас багаторазового використання для SFTP FILES UPLOAD / DOWNLOAD за допомогою бібліотеки JSch.

Використання завантаження:

SFTPFileCopy upload = new SFTPFileCopy(true, /path/to/sourcefile.png", /path/to/destinationfile.png");

Використання завантажень:

SFTPFileCopy download = new SFTPFileCopy(false, "/path/to/sourcefile.png", "/path/to/destinationfile.png");

Код класу:

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UIKeyboardInteractive;
import com.jcraft.jsch.UserInfo;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.swing.JOptionPane;
import menue.Menue;

public class SFTPFileCopy1 {

    public SFTPFileCopy1(boolean upload, String sourcePath, String destPath) throws FileNotFoundException, IOException {
        Session session = null;
        Channel channel = null;
        ChannelSftp sftpChannel = null;
        try {
            JSch jsch = new JSch();
            //jsch.setKnownHosts("/home/user/.putty/sshhostkeys");
            session = jsch.getSession("login", "mysite.com", 22);
            session.setPassword("password");

            UserInfo ui = new MyUserInfo() {
                public void showMessage(String message) {

                    JOptionPane.showMessageDialog(null, message);

                }

                public boolean promptYesNo(String message) {

                    Object[] options = {"yes", "no"};

                    int foo = JOptionPane.showOptionDialog(null,
                            message,
                            "Warning",
                            JOptionPane.DEFAULT_OPTION,
                            JOptionPane.WARNING_MESSAGE,
                            null, options, options[0]);

                    return foo == 0;

                }
            };
            session.setUserInfo(ui);

            session.setConfig("StrictHostKeyChecking", "no");
            session.connect();
            channel = session.openChannel("sftp");
            channel.setInputStream(System.in);
            channel.setOutputStream(System.out);
            channel.connect();
            sftpChannel = (ChannelSftp) channel;

            if (upload) { // File upload.
                byte[] bufr = new byte[(int) new File(sourcePath).length()];
                FileInputStream fis = new FileInputStream(new File(sourcePath));
                fis.read(bufr);
                ByteArrayInputStream fileStream = new ByteArrayInputStream(bufr);
                sftpChannel.put(fileStream, destPath);
                fileStream.close();
            } else { // File download.
                byte[] buffer = new byte[1024];
                BufferedInputStream bis = new BufferedInputStream(sftpChannel.get(sourcePath));
                OutputStream os = new FileOutputStream(new File(destPath));
                BufferedOutputStream bos = new BufferedOutputStream(os);
                int readCount;
                while ((readCount = bis.read(buffer)) > 0) {
                    bos.write(buffer, 0, readCount);
                }
                bis.close();
                bos.close();
            }
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            if (sftpChannel != null) {
                sftpChannel.exit();
            }
            if (channel != null) {
                channel.disconnect();
            }
            if (session != null) {
                session.disconnect();
            }
        }
    }

    public static abstract class MyUserInfo
            implements UserInfo, UIKeyboardInteractive {

        public String getPassword() {
            return null;
        }

        public boolean promptYesNo(String str) {
            return false;
        }

        public String getPassphrase() {
            return null;
        }

        public boolean promptPassphrase(String message) {
            return false;
        }

        public boolean promptPassword(String message) {
            return false;
        }

        public void showMessage(String message) {
        }

        public String[] promptKeyboardInteractive(String destination,
                String name,
                String instruction,
                String[] prompt,
                boolean[] echo) {

            return null;
        }
    }
}


1

Я використовую цей SFTP API під назвою Zehon, він чудовий, тому простий у використанні з великою кількістю зразкового коду. Ось сайт http://www.zehon.com


2
Зехон здається мертвим. А де джерело? Що за "ліцензія" стоїть за "безкоштовною"?
rü-

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.