SFTP aracılığıyla bir sunucudan dosya nasıl alınır?


228

Java kullanarak SFTP (FTPS aksine) kullanarak bir sunucudan bir dosya almaya çalışıyorum. Bunu nasıl yapabilirim?

Yanıtlar:


198

Başka bir seçenek de JSch kütüphanesine bakmayı düşünmektir . JSch, Eclipse, Ant ve Apache Commons HttpClient dahil olmak üzere birkaç büyük açık kaynak projesi için tercih edilen kütüphane gibi görünüyor.

Hem kullanıcı / geçiş hem de sertifika tabanlı girişleri ve diğer tüm lezzetli SSH2 özelliklerini barındırır.

İşte SFTP üzerinden basit bir uzak dosya alma. Hata işleme okuyucu için bir alıştırma olarak bırakıldı :-)

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, fark ettim - Jsch kullanırken - sftp sunucusundaki dosyaları kaldırma çalışmıyor. Ayrıca dosyaları yeniden adlandırmak da işe yaramaz. Herhangi bir fikir lütfen ??? Andy

1
Üzgünüm, şu anda üzerinde çalıştığım bir şey değil. (Lütfen bu tür yanıtları yorum olarak bırakın - bu mesaj gibi - orijinal soruya yeni bir cevap olarak değil)
Cheekysoft

1
Oturum atamasından sonra bu kod bloğu nedir? Daha önce hiç görmediğim bazı süslü Java sözdizimi mi? Eğer öyleyse - bu şekilde yazılmayı ne başarır?
Michael Peterson

3
@ p1x3l5 standart java sözdizimi bir bloğun herhangi bir yere eklenmesine izin verir; isterseniz değişken kapsam üzerinde daha ince kontrol sağlamak için kullanılabilir. Bununla birlikte, bu durumda, iki uygulama seçimini belirtmeye yardımcı olmak yalnızca görsel bir yardımcıdır: ya kullanıcıdan parola isteyen etkileşimli sürümü kullanın ya da kullanıcı müdahalesi gerektirmeyen, ancak ek bir güvenlik riski gerektiren sabit kodlu bir parola kullanın.
Cheekysoft

109

İşte ssh anahtar denetimi hakkında endişelenmenize gerek kalmadan JSch kullanan bir örneğin tam kaynak kodu .

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
Her finallyzaman çalıştığından emin olmak için kanal temizleme kodunu dahil etmek için bir blok kullanılmalıdır.
hotshot309

Şu an bu istisnayı alıyorum: 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'nin 0 veya 1 ek bağımlılığa sahip olduğunu gördüm. Sıkıştırmayı devre dışı bırakırsanız JZLIB bağımlılığını yoksayabilirsiniz. // sıkıştırma oturumunu devre dışı bırak. setConfig ("sıkıştırma.s2c", "yok"); session.setConfig ("sıkıştırma.c2s", "yok");
englebart

1
Sıkı ana bilgisayar kontrolü olmadan, ortadaki adam saldırısına maruz kalırsınız.
rustyx

44

Aşağıda Apache Common VFS kullanan bir örnek verilmiştir:

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
Yapılacak başka bir güzel şey de zaman aşımını ayarlamaktır, böylece uzak sistem çevrimdışıysa, sonsuza kadar orada durmazsınız. Bunu, ana bilgisayar anahtarı denetimi devre dışı bırakma için yapıldığı gibi yapabilirsiniz: SftpFileSystemConfigBuilder.getInstance (). SetTimeout (fsOptions, 5000);
Scott Jones

Aynı anda birden fazla SFTP istemcisi kullanırken bu bağlantıyı nasıl kapatmayı tavsiye edersiniz?
2Big2BeSmall

2
Şifrem @ simgesi içeriyorsa ne olur?
Kullanıcı3

23

Bu, http://sourceforge.net/projects/sshtools/ (açıklığa kavuşturmak için çoğu hata işleme atlandı) ile bulduğum çözümdü . Bu bir alıntıdır blogumda

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
Kabul ediyorum (gecikmeli olarak), orijinal site / indirme için iyi çalıştı, ancak yenisi için çalışmaktan vazgeçti. JSch'e geçme sürecindeyim
David Hayes

23

Jsch'in üstünde güzel bir soyutlama, SFTP dosyalarına erişmeyi ve yazmayı neredeyse şeffaf hale getiren sanal bir dosya sistemi API'si sunan Apache commons- vfs'dir . Bizim için iyi çalıştı.


1
paylaşımlı anahtarları commons-vfs ile birlikte kullanmak mümkün müdür?
Benedikt Waldvogel

2
Evet öyle. Standart olmayan kimliklere ihtiyacınız varsa SftpFileSystemConfigBuilder.getInstance (). SetIdentities (...) öğesini çağırabilirsiniz.
Russ Hayward

Önceden paylaşılan anahtarları kullanabilirsiniz. Ancak bu anahtarların parola olmadan olması gerekir. OtrosLogViewer VFS ile SSH anahtar yetkilendirmesi kullanıyor ancak anahtardan parolanın kaldırılmasını gerektiriyor ( code.google.com/p/otroslogviewer/wiki/SftpAuthPubKey )
KrzyH 18:05

19

SFTP için 3 olgun Java kütüphanesi arasında güzel bir karşılaştırma var: Commons VFS, SSHJ ve JSch

Özetle SSHJ en açık API'ya sahiptir ve Commons VFS tarafından sağlanan diğer depolama desteğine ihtiyacınız yoksa bunların en iyisi.

Burada gelen SSHJ örnek düzenlenir 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
Dosyayı InputStream olarak almanın bir yolu var mı?
Johan

2
2019'da sshj hala iyi korunuyor ve Alpakka (Akka) projesi tarafından kullanılıyor
Maxence

13

Apache Commons SFTP kütüphanesi

Tüm örnekler için ortak java özellikleri dosyası

serverAddress = 111.222.333.444

userId = MyUserID

password =

remoteDirectory = ürünler /

localDirectory = ithalat /

SFTP kullanarak uzak sunucuya dosya yükle

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 kullanarak uzak sunucudan dosya indirme

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 kullanarak uzak sunucudaki bir dosyayı silme

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

}


sunucuya dosyaları kopyalamak için ssh-key (ortak anahtar) varken nasıl yapılandırılır. Çünkü sunucum ile uzak sunucu arasında ssh_trust yapmam gerekiyor.
MS Parmar

7

hierynomus / sshj , SFTP sürüm 3'ün tam bir uygulamasına sahiptir (OpenSSH'nin uyguladığı şey)

SFTPUpload.java örnek kodu

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
iyi iş!! ana sayfadaki bir örnek de yardımcı olabilir.
OhadR

4

JSch kütüphanesi, SFTP sunucusundan dosya okumak için kullanılabilecek güçlü bir kütüphanedir. Aşağıda, SFTP konumundan satır satır dosyayı okumak için test edilmiş kod verilmiştir

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

Tüm program için lütfen bloga bakın .


3

Andy, uzak sistemdeki dosyayı silmek için (channelExec)JSch kullanmanız ve silmek için unix / linux komutlarını iletmeniz gerekir.


2

Bağlantı havuzlarını ve eşzamansız işlemleri destekleyen olgun, sağlam bir SFTP istemci kütüphanesi olan edtFTPj / PRO'yu deneyin . Ayrıca FTP ve FTPS'yi de destekler, böylece güvenli dosya aktarımı için tüm temeller kapsanır.



2

Yukarıdaki yanıtlar çok yardımcı olsa da, "kırık kanal", "rsa anahtarı bilinmiyor" ve "paket bozuk" gibi çeşitli istisnalarla karşı karşıya kalmaları için bir gün geçirdim.

Aşağıda JSch kütüphanesini kullanarak SFTP DOSYALARI YÜKLEME / İNDİRME için yeniden kullanılabilir bir sınıf bulunmaktadır.

Yükleme kullanımı:

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

İndirme kullanımı:

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

Sınıf kodu:

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

Zehon adlı bu SFTP API'sini kullanıyorum, harika, çok fazla örnek kodla kullanımı çok kolay. İşte http://www.zehon.com sitesi


2
Zehon ölü gibi görünüyor. Ve kaynak nerede? "Özgür" ün arkasında hangi "lisans" vardır?
rü-

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.