Bagaimana cara mengambil file dari server melalui SFTP?

228

Saya mencoba untuk mengambil file dari server menggunakan SFTP (bukan FTPS) menggunakan Java. Bagaimana saya bisa melakukan ini?

David Hayes
sumber

Jawaban:

198

Pilihan lain adalah mempertimbangkan melihat perpustakaan JSch . JSch tampaknya menjadi perpustakaan pilihan untuk beberapa proyek open source besar, termasuk Eclipse, Ant dan Apache Commons HttpClient, di antara yang lainnya.

Ini mendukung baik pengguna / pass dan login berbasis sertifikat dengan baik, serta semua sejumlah fitur SSH2 yummy lainnya.

Berikut ini file jarak jauh sederhana yang diambil dari SFTP. Penanganan kesalahan dibiarkan sebagai latihan untuk pembaca :-)

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();
Cheekysoft
sumber
1
Cheekysoft, saya perhatikan - saat menggunakan Jsch - menghapus file di sftp-server tidak berfungsi. Mengganti nama file juga tidak berfungsi. Ada ide tolong ??? Andy
1
Maaf, ini bukan sesuatu yang saya kerjakan saat ini. (Silakan coba dan tinggalkan tanggapan semacam ini sebagai komentar - seperti pesan ini - dan bukan sebagai jawaban baru untuk pertanyaan awal)
Cheekysoft
1
Apa itu blok kode setelah penugasan sesi? Apakah itu beberapa sintaks Java mewah yang belum pernah saya lihat? Jika demikian - apa artinya ditulis seperti itu?
Michael Peterson
3
@ p1x3l5 sintaks java standar memungkinkan blok untuk dimasukkan di mana saja; itu dapat digunakan untuk memberikan kontrol yang lebih baik atas ruang lingkup variabel, jika Anda mau. Namun, dalam hal ini, itu hanya bantuan visual untuk membantu menunjukkan dua pilihan implementasi: baik menggunakan versi interaktif yang meminta kata sandi dari pengguna, atau menggunakan kata sandi yang dikode keras yang tidak memerlukan intervensi pengguna tetapi bisa dibilang risiko keamanan tambahan.
Cheekysoft
109

Berikut adalah kode sumber lengkap contoh menggunakan JSch tanpa harus khawatir tentang pemeriksaan kunci 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();
        }
    }
}
Iraklis
sumber
15
Sebuah finallyblok harus digunakan untuk menyertakan saluran kode yang bersih-up, untuk memastikan bahwa itu selalu berjalan.
hotshot309
Saya mendapatkan pengecualian ini sekarang: 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
Saya menemukan JSCH memiliki 0 atau 1 dependensi tambahan. Anda dapat mengabaikan ketergantungan JZLIB jika Anda menonaktifkan kompresi. // nonaktifkan kompresi session.setConfig ("compression.s2c", "none"); session.setConfig ("compression.c2s", "none");
englebart
1
Tanpa host ketat, Anda rentan terhadap serangan dari orang ke orang.
rustyx
44

Di bawah ini adalah contoh menggunakan 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);
Chris J
sumber
5
Hal lain yang menyenangkan untuk dilakukan adalah mengatur batas waktu, sehingga jika sistem jarak jauh sedang offline, Anda tidak bertahan selamanya. Anda dapat melakukan ini seperti yang dilakukan untuk menonaktifkan tanda kunci host: SftpFileSystemConfigBuilder.getInstance (). SetTimeout (fsOptions, 5000);
Scott Jones
Bagaimana Anda menyarankan untuk menutup koneksi ini ketika menggunakan beberapa klien SFTP pada saat yang sama?
2Big2BeSmall
2
Bagaimana jika kata sandi saya mengandung simbol @?
User3
23

Ini adalah solusi yang saya buat dengan http://sourceforge.net/projects/sshtools/ (kebanyakan penanganan kesalahan dihilangkan untuk kejelasan). Ini adalah kutipan dari blog saya

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();
David Hayes
sumber
7
Saya setuju (terlambat), itu berfungsi dengan baik untuk situs asli / unduhan yang saya butuhkan tetapi direvisi untuk bekerja untuk yang baru. Saya sedang dalam proses beralih ke JSch
David Hayes
23

Sebuah abstraksi yang bagus di atas Jsch adalah Apache commons-vfs yang menawarkan API sistem file virtual yang membuat mengakses dan menulis file SFTP hampir transparan. Bekerja dengan baik untuk kita.

Boris Terzic
sumber
1
apakah mungkin menggunakan kunci yang dibagikan sebelumnya dalam kombinasi dengan commons-vfs?
Benedikt Waldvogel
2
Ya itu. Jika Anda memerlukan identitas non-standar, Anda dapat menghubungi SftpFileSystemConfigBuilder.getInstance (). SetIdentities (...).
Russ Hayward
Anda dapat menggunakan kunci yang dibagikan sebelumnya. Tetapi kunci ini harus tanpa kata sandi. OtrosLogViewer menggunakan otorisasi kunci SSH dengan VFS tetapi harus menghapus frasa sandi dari kunci ( code.google.com/p/otroslogviewer/wiki/SftpAuthPubKey )
KrzyH
19

Ada perbandingan yang bagus dari 3 perpustakaan Java dewasa untuk SFTP: Commons VFS, SSHJ dan JSch

Singkatnya SSHJ memiliki API paling jelas dan ini yang terbaik jika mereka tidak membutuhkan dukungan penyimpanan lain yang disediakan oleh Commons VFS.

Berikut ini contoh SSHJ yang diedit dari 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();
}
Sasha
sumber
2
Apakah ada cara untuk mendapatkan file sebagai InputStream?
Johan
2
sshj pada tahun 2019 masih terpelihara dengan baik dan digunakan oleh proyek Alpakka (Akka)
Maxence
13

Pustaka Apache Commons SFTP

File properti java umum untuk semua contoh

serverAddress = 111.222.333.444

userId = myUserId

kata sandi = myPassword

remoteDirectory = produk /

localDirectory = impor /

Unggah file ke server jauh menggunakan 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;
 }


}

Unduh file dari server jauh menggunakan 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;
 }

}

Hapus file di server jauh menggunakan 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;
 }

}
AZ_
sumber
cara mengkonfigurasi sambil memiliki ssh-key (kunci publik) untuk menyalin file di server. Karena saya perlu membuat ssh_trust antara server saya dan server jarak jauh.
MS Parmar
7

hierynomus / sshj memiliki implementasi lengkap SFTP versi 3 (apa yang diterapkan OpenSSH)

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

}
shikhar
sumber
2
pekerjaan yang baik!! contoh di halaman utama bisa sangat membantu.
OhadR
4

Pustaka JSch adalah pustaka yang kuat yang dapat digunakan untuk membaca file dari server SFTP. Di bawah ini adalah kode yang diuji untuk membaca file dari lokasi SFTP baris demi baris

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

Silakan merujuk blog untuk seluruh program.

Ankur jain
sumber
3

Andy, untuk menghapus file pada sistem jarak jauh Anda perlu menggunakan (channelExec)JSch dan mengirimkan perintah unix / linux untuk menghapusnya.

Rotan Pushpinder
sumber
2

Coba edtFTPj / PRO , pustaka klien SFTP yang matang dan kuat yang mendukung kumpulan koneksi dan operasi asinkron. Juga mendukung FTP dan FTPS sehingga semua basis untuk transfer file aman tercakup.

Bruce Blackshaw
sumber
2

Meskipun jawaban di atas sangat membantu, saya telah menghabiskan satu hari untuk membuatnya bekerja, menghadapi berbagai pengecualian seperti "saluran rusak", "kunci rsa tidak diketahui" dan "paket rusak".

Di bawah ini adalah kelas reusable yang berfungsi untuk SFTP FILES UPLOAD / UNDUH menggunakan perpustakaan JSch.

Penggunaan unggahan:

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

Penggunaan unduhan:

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

Kode kelas:

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;
        }
    }
}
Zon
sumber
1

Saya menggunakan SFTP API yang disebut Zehon ini, sangat bagus, sehingga mudah digunakan dengan banyak kode sampel. Berikut adalah situs http://www.zehon.com


sumber
2
Zehon tampaknya sudah mati. Dan dari mana sumbernya? Apa 'lisensi' di balik 'gratis'?
rü-
0

Solusi terbaik yang saya temukan adalah Paramiko . Ada versi Java.

Brian Clapper
sumber
github.com/terencehonles/jaramiko ditinggalkan demi JSch (lihat pemberitahuan di github).
rü-