java实现sftp文件上传_【转】JSch - Java实现的SFTP(文件上传详解篇)

本文详细介绍了如何使用Java的JSch库实现SFTP文件上传,包括JSch的介绍、SFTP的概念、如何创建SFTP通道、JSch的文件传输模式以及如何监控文件传输进度。示例代码展示了不同方式的文件上传和进度监控实现。
摘要由CSDN通过智能技术生成

JSch是Java Secure Channel的缩写。JSch是一个SSH2的纯Java实现。它允许你连接到一个SSH服务器,并且可以使用端口转发,X11转发,文件传输等,当然你也可以集成它的功能到你自己的应用程序。

本文只介绍如何使用JSch实现的SFTP功能。

SFTP是Secure File Transfer Protocol的缩写,安全文件传送协议。可以为传输文件提供一种安全的加密方法。SFTP 为 SSH的一部份,是一种传输文件到服务器的安全方式。SFTP是使用加密传输认证信息和传输的数据,所以,使用SFTP是非常安全的。但是,由于这种传输方式使用了加密/解密技术,所以传输效率比普通的FTP要低得多,如果您对网络安全性要求更高时,可以使用SFTP代替FTP。(来自百度的解释)

要使用JSch,需要下载它的jar包,请从官网下载它:http://www.jcraft.com/jsch/

ChannelSftp类是JSch实现SFTP核心类,它包含了所有SFTP的方法,如:

put():      文件上传

get():      文件下载

cd():       进入指定目录

ls():       得到指定目录下的文件列表

rename():   重命名指定文件或目录

rm():       删除指定文件

mkdir():    创建目录

rmdir():    删除目录

等等(这里省略了方法的参数,put和get都有多个重载方法,具体请看源代码,这里不一一列出。)

JSch支持三种文件传输模式:

OVERWRITE

完全覆盖模式,这是JSch的默认文件传输模式,即如果目标文件已经存在,传输的文件将完全覆盖目标文件,产生新的文件。

RESUME

恢复模式,如果文件已经传输一部分,这时由于网络或其他任何原因导致文件传输中断,如果下一次传输相同的文件,

则会从上一次中断的地方续传。

APPEND

追加模式,如果目标文件已存在,传输的文件将在目标文件后追加。

创建ChannelSftp对象

编写一个工具类,根据ip,用户名及密码得到一个SFTP channel对象,即ChannelSftp的实例对象,在应用程序中就可以使用该对象来调用SFTP的各种操作方法。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagecom.longyg.sftp;2

3 importjava.util.Map;4 importjava.util.Properties;5 importorg.apache.log4j.Logger;6 importcom.jcraft.jsch.Channel;7 importcom.jcraft.jsch.ChannelSftp;8 importcom.jcraft.jsch.JSch;9 importcom.jcraft.jsch.JSchException;10 importcom.jcraft.jsch.Session;11 public classSFTPChannel {12 Session session = null;13 Channel channel = null;14 private static final Logger LOG = Logger.getLogger(SFTPChannel.class.getName());15 public ChannelSftp getChannel(Map sftpDetails, int timeout) throwsJSchException {16 String ftpHost =sftpDetails.get(SFTPConstants.SFTP_REQ_HOST);17 String port =sftpDetails.get(SFTPConstants.SFTP_REQ_PORT);18 String ftpUserName =sftpDetails.get(SFTPConstants.SFTP_REQ_USERNAME);19 String ftpPassword =sftpDetails.get(SFTPConstants.SFTP_REQ_PASSWORD);20 int ftpPort =SFTPConstants.SFTP_DEFAULT_PORT;21 if (port != null && !port.equals("")) {22 ftpPort =Integer.valueOf(port);23 }24 JSch jsch = new JSch(); //创建JSch对象

25 session = jsch.getSession(ftpUserName, ftpHost, ftpPort); //根据用户名,主机ip,端口获取一个Session对象

26 LOG.debug("Session created.");27 if (ftpPassword != null) {28 session.setPassword(ftpPassword); //设置密码

29 }30 Properties config = newProperties();31 config.put("StrictHostKeyChecking", "no");32 session.setConfig(config); //为Session对象设置properties

33 session.setTimeout(timeout); //设置timeout时间

34 session.connect(); //通过Session建立链接

35 LOG.debug("Session connected.");36 LOG.debug("Opening Channel.");37 channel = session.openChannel("sftp"); //打开SFTP通道

38 channel.connect(); //建立SFTP通道的连接

39 LOG.debug("Connected successfully to ftpHost = " + ftpHost + ",as ftpUserName = " +ftpUserName40 + ", returning: " +channel);41 return(ChannelSftp) channel;42 }43 public void closeChannel() throwsException {44 if (channel != null) {45 channel.disconnect();46 }47 if (session != null) {48 session.disconnect();49 }50 }51 }

SFTPChannel.java

SFTPConstants是一个静态成员变量类:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagecom.longyg.sftp;2

3 public classSFTPConstants {4 public static final String SFTP_REQ_HOST = "host";5 public static final String SFTP_REQ_PORT = "port";6 public static final String SFTP_REQ_USERNAME = "username";7 public static final String SFTP_REQ_PASSWORD = "password";8 public static final int SFTP_DEFAULT_PORT = 22;9 public static final String SFTP_REQ_LOC = "location";10 }

SFTPConstants.java

文件上传

实现文件上传可以调用ChannelSftp对象的put方法。ChannelSftp中有12个put方法的重载方法:

public void put(String src, String dst)

将本地文件名为src的文件上传到目标服务器,目标文件名为dst,若dst为目录,则目标文件名将与src文件名相同。

采用默认的传输模式:OVERWRITE

public void put(String src, String dst, int mode)

将本地文件名为src的文件上传到目标服务器,目标文件名为dst,若dst为目录,则目标文件名将与src文件名相同。

指定文件传输模式为mode(mode可选值为:ChannelSftp.OVERWRITE,ChannelSftp.RESUME,

ChannelSftp.APPEND)

public void put(String src, String dst, SftpProgressMonitor monitor)

将本地文件名为src的文件上传到目标服务器,目标文件名为dst,若dst为目录,则目标文件名将与src文件名相同。

采用默认的传输模式:OVERWRITE

并使用实现了SftpProgressMonitor接口的monitor对象来监控文件传输的进度。

public void put(String src, String dst,

SftpProgressMonitor monitor, int mode)

将本地文件名为src的文件上传到目标服务器,目标文件名为dst,若dst为目录,则目标文件名将与src文件名相同。

指定传输模式为mode

并使用实现了SftpProgressMonitor接口的monitor对象来监控文件传输的进度。

public void put(InputStream src, String dst)

将本地的input stream对象src上传到目标服务器,目标文件名为dst,dst不能为目录。

采用默认的传输模式:OVERWRITE

public void put(InputStream src, String dst, int mode)

将本地的input stream对象src上传到目标服务器,目标文件名为dst,dst不能为目录。

指定文件传输模式为mode

public void put(InputStream src, String dst, SftpProgressMonitor monitor)

将本地的input stream对象src上传到目标服务器,目标文件名为dst,dst不能为目录。

采用默认的传输模式:OVERWRITE

并使用实现了SftpProgressMonitor接口的monitor对象来监控传输的进度。

public void put(InputStream src, String dst,

SftpProgressMonitor monitor, int mode)

将本地的input stream对象src上传到目标服务器,目标文件名为dst,dst不能为目录。

指定文件传输模式为mode

并使用实现了SftpProgressMonitor接口的monitor对象来监控传输的进度。

public OutputStream put(String dst)

该方法返回一个输出流,可以向该输出流中写入数据,最终将数据传输到目标服务器,目标文件名为dst,dst不能为目录。

采用默认的传输模式:OVERWRITE

public OutputStream put(String dst, final int mode)

该方法返回一个输出流,可以向该输出流中写入数据,最终将数据传输到目标服务器,目标文件名为dst,dst不能为目录。

指定文件传输模式为mode

public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode)

该方法返回一个输出流,可以向该输出流中写入数据,最终将数据传输到目标服务器,目标文件名为dst,dst不能为目录。

指定文件传输模式为mode

并使用实现了SftpProgressMonitor接口的monitor对象来监控传输的进度。

public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode, long offset)

该方法返回一个输出流,可以向该输出流中写入数据,最终将数据传输到目标服务器,目标文件名为dst,dst不能为目录。

指定文件传输模式为mode

并使用实现了SftpProgressMonitor接口的monitor对象来监控传输的进度。

offset指定了一个偏移量,从输出流偏移offset开始写入数据。

应用实例:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagecom.longyg.sftp;2

3 importjava.util.HashMap;4 importjava.util.Map;5 importcom.jcraft.jsch.ChannelSftp;6 public classSFTPTest {7 publicSFTPChannel getSFTPChannel() {8 return newSFTPChannel();9 }10 /**

11 *@paramargs12 *@throwsException13 */

14 public static void main(String[] args) throwsException {15 SFTPTest test = newSFTPTest();16 Map sftpDetails = new HashMap();17 //设置主机ip,端口,用户名,密码

18 sftpDetails.put(SFTPConstants.SFTP_REQ_HOST, "10.9.167.55");19 sftpDetails.put(SFTPConstants.SFTP_REQ_USERNAME, "root");20 sftpDetails.put(SFTPConstants.SFTP_REQ_PASSWORD, "arthur");21 sftpDetails.put(SFTPConstants.SFTP_REQ_PORT, "22");22

23 String src = "D:\\DevSoft\\HB-SnagIt1001.rar"; //本地文件名

24 String dst = "/home/omc/ylong/sftp/HB-SnagIt1001.rar"; //目标文件名

25

26 SFTPChannel channel =test.getSFTPChannel();27 ChannelSftp chSftp = channel.getChannel(sftpDetails, 60000);28

29 /**

30 * 代码段131 OutputStream out = chSftp.put(dst, ChannelSftp.OVERWRITE); // 使用OVERWRITE模式32 byte[] buff = new byte[1024 * 256]; // 设定每次传输的数据块大小为256KB33 int read;34 if (out != null) {35 System.out.println("Start to read input stream");36 InputStream is = new FileInputStream(src);37 do {38 read = is.read(buff, 0, buff.length);39 if (read > 0) {40 out.write(buff, 0, read);41 }42 out.flush();43 } while (read >= 0);44 System.out.println("input stream read done.");45 }46 **/

47

48 chSftp.put(src, dst, ChannelSftp.OVERWRITE); //代码段249

50 //chSftp.put(new FileInputStream(src), dst, ChannelSftp.OVERWRITE);//代码段3

51

52 chSftp.quit();53 channel.closeChannel();54 }55 }

SFTPTest.java

注:请分别将代码段1,代码段2,代码段3取消注释,运行程序来进行测试。这三段代码分别演示了如何使用JSch的不同的put方法来进行文件上传。

代码段1:采用向put方法返回的输出流中写入数据的方式来传输文件。 需要由程序来决定写入什么样的数据,这里是将本地文件的输入流写入输出流。采用这种方式的好处是,可以自行设定每次写入输出流的数据块大小,如本示例中的语句:

byte[] buff = new byte[1024 * 256]; //设定每次传输的数据块大小为256KB

代码段2:直接将本地文件名为src的文件上传到目标服务器,目标文件名为dst。(注:使用这个方法时,dst可以是目录,当dst是目录时,上传后的目标文件名将与src文件名相同)

代码段3:将本地文件名为src的文件输入流上传到目标服务器,目标文件名为dst。

这三段代码实现的功能是一样的,都是将本地的文件src上传到了服务器的dst文件。使用时可根据具体情况选择使用哪种实现方式。

监控传输进度

从前面的介绍中知道,JSch支持在文件传输时对传输进度的监控。可以实现JSch提供的SftpProgressMonitor接口来完成这个功能。

SftpProgressMonitor接口类的定义为:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagecom.jcraft.jsch;2

3 public interfaceSftpProgressMonitor{4 public static final int PUT=0;5 public static final int GET=1;6 void init(int op, String src, String dest, longmax);7 boolean count(longcount);8 voidend();9 }

SftpProgressMonitor.java

init():当文件开始传输时,调用init方法。

count(): 当每次传输了一个数据块后,调用count方法,count方法的参数为这一次传输的数据块大小。

end():当传输结束时,调用end方法。

下面是一个简单的实现:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagecom.longyg.sftp;2

3 importcom.jcraft.jsch.SftpProgressMonitor;4

5 public class MyProgressMonitor implementsSftpProgressMonitor {6 private longtransfered;7 @Override8 public boolean count(longcount) {9 transfered = transfered +count;10 System.out.println("Currently transferred total size: " + transfered + " bytes");11 return true;12 }13 @Override14 public voidend() {15 System.out.println("Transferring done.");16 }17 @Override18 public void init(int op, String src, String dest, longmax) {19 System.out.println("Transferring begin.");20 }21 }

MyProgressMonitor.java

此时如果改变SFTPTest main方法里调用的put方法,即可实现监控传输进度:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagecom.longyg.sftp;2

3 importjava.util.HashMap;4 importjava.util.Map;5 importcom.jcraft.jsch.ChannelSftp;6

7 public classSFTPTest {8 publicSFTPChannel getSFTPChannel() {9 return newSFTPChannel();10 }11 /**

12 *@paramargs13 *@throwsException14 */

15 public static void main(String[] args) throwsException {16 SFTPTest test = newSFTPTest();17 Map sftpDetails = new HashMap();18 //设置主机ip,端口,用户名,密码

19 sftpDetails.put(SFTPConstants.SFTP_REQ_HOST, "10.9.167.55");20 sftpDetails.put(SFTPConstants.SFTP_REQ_USERNAME, "root");21 sftpDetails.put(SFTPConstants.SFTP_REQ_PASSWORD, "arthur");22 sftpDetails.put(SFTPConstants.SFTP_REQ_PORT, "22");23

24 String src = "D:\\DevSoft\\HB-SnagIt1001.rar"; //本地文件名

25 String dst = "/home/omc/ylong/sftp/HB-SnagIt1001.rar"; //目标文件名

26

27 SFTPChannel channel =test.getSFTPChannel();28 ChannelSftp chSftp = channel.getChannel(sftpDetails, 60000);29

30 /**

31 * 代码段132 OutputStream out = chSftp.put(dst, new MyProgressMonitor(), ChannelSftp.OVERWRITE); // 使用OVERWRITE模式33 byte[] buff = new byte[1024 * 256]; // 设定每次传输的数据块大小为256KB34 int read;35 if (out != null) {36 System.out.println("Start to read input stream");37 InputStream is = new FileInputStream(src);38 do {39 read = is.read(buff, 0, buff.length);40 if (read > 0) {41 out.write(buff, 0, read);42 }43 out.flush();44 } while (read >= 0);45 System.out.println("input stream read done.");46 }47 **/

48

49 chSftp.put(src, dst, new MyProgressMonitor(), ChannelSftp.OVERWRITE); //代码段250

51 //chSftp.put(new FileInputStream(src), dst, new MyProgressMonitor(), ChannelSftp.OVERWRITE);//代码段3

52

53 chSftp.quit();54 channel.closeChannel();55 }56 }

SFTPTest.java

注意修改的内容仅仅是put方法,在put方法中增加了SftpProgressMonitor的实现类对象monitor作为参数,即添加了对进度监控的支持。

运行,输出结果如下:

1 Start to read input stream2 Currently transferred total size: 262144bytes3 Currently transferred total size: 524288bytes4 Currently transferred total size: 786432bytes5 Currently transferred total size: 1048576bytes6 Currently transferred total size: 1310720bytes7 Currently transferred total size: 1572864bytes8 Currently transferred total size: 1835008bytes9 Currently transferred total size: 2097152bytes10 Currently transferred total size: 2359296bytes11 Currently transferred total size: 2621440bytes12 Currently transferred total size: 2883584bytes13 Currently transferred total size: 3145728bytes14 Currently transferred total size: 3407872bytes15 Currently transferred total size: 3670016bytes16 Currently transferred total size: 3848374bytes17 input stream read done.

当然这个SftpProgressMonitor的实现实在太简单。JSch每次传输一个数据块,就会调用count方法来实现主动进度通知。

现在我们希望每间隔一定的时间才获取一下文件传输的进度。。。看看下面的SftpProgressMonitor实现:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagecom.longyg.sftp;2

3 importjava.text.DecimalFormat;4 importjava.util.Timer;5 importjava.util.TimerTask;6 importcom.jcraft.jsch.SftpProgressMonitor;7

8 public class FileProgressMonitor extends TimerTask implementsSftpProgressMonitor {9

10 private long progressInterval = 5 * 1000; //默认间隔时间为5秒

11

12 private boolean isEnd = false; //记录传输是否结束

13

14 private long transfered; //记录已传输的数据总大小

15

16 private long fileSize; //记录文件总大小

17

18 private Timer timer; //定时器对象

19

20 private boolean isScheduled = false; //记录是否已启动timer记时器

21

22 public FileProgressMonitor(longfileSize) {23 this.fileSize =fileSize;24 }25

26 @Override27 public voidrun() {28 if (!isEnd()) { //判断传输是否已结束

29 System.out.println("Transfering is in progress.");30 long transfered =getTransfered();31 if (transfered != fileSize) { //判断当前已传输数据大小是否等于文件总大小

32 System.out.println("Current transfered: " + transfered + " bytes");33 sendProgressMessage(transfered);34 } else{35 System.out.println("File transfering is done.");36 setEnd(true); //如果当前已传输数据大小等于文件总大小,说明已完成,设置end

37 }38 } else{39 System.out.println("Transfering done. Cancel timer.");40 stop(); //如果传输结束,停止timer记时器

41 return;42 }43 }44

45 public voidstop() {46 System.out.println("Try to stop progress monitor.");47 if (timer != null) {48 timer.cancel();49 timer.purge();50 timer = null;51 isScheduled = false;52 }53 System.out.println("Progress monitor stoped.");54 }55

56 public voidstart() {57 System.out.println("Try to start progress monitor.");58 if (timer == null) {59 timer = newTimer();60 }61 timer.schedule(this, 1000, progressInterval);62 isScheduled = true;63 System.out.println("Progress monitor started.");64 }65

66 /**

67 * 打印progress信息68 *@paramtransfered69 */

70 private void sendProgressMessage(longtransfered) {71 if (fileSize != 0) {72 double d = ((double)transfered * 100)/(double)fileSize;73 DecimalFormat df = new DecimalFormat( "#.##");74 System.out.println("Sending progress message: " + df.format(d) + "%");75 } else{76 System.out.println("Sending progress message: " +transfered);77 }78 }79 /**

80 * 实现了SftpProgressMonitor接口的count方法81 */

82 public boolean count(longcount) {83 if (isEnd()) return false;84 if (!isScheduled) {85 start();86 }87 add(count);88 return true;89 }90 /**

91 * 实现了SftpProgressMonitor接口的end方法92 */

93 public voidend() {94 setEnd(true);95 System.out.println("transfering end.");96 }97

98 private synchronized void add(longcount) {99 transfered = transfered +count;100 }101

102 private synchronized longgetTransfered() {103 returntransfered;104 }105

106 public synchronized void setTransfered(longtransfered) {107 this.transfered =transfered;108 }109

110 private synchronized void setEnd(booleanisEnd) {111 this.isEnd =isEnd;112 }113

114 private synchronized booleanisEnd() {115 returnisEnd;116 }117 public void init(int op, String src, String dest, longmax) {118 //Not used for putting InputStream

119 }120 }

FileProgressMonitor.java

再次修改SFTPTest main方法里的put方法,改为使用新的SftpProgressMonitor的实现类对象monitor作为参数,注意新的monitor对象的构造函数需要传入文件大小作为参数:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagecom.longyg.sftp;2

3 importjava.io.File;4 importjava.util.HashMap;5 importjava.util.Map;6 importcom.jcraft.jsch.ChannelSftp;7

8 public classSFTPTest {9 publicSFTPChannel getSFTPChannel() {10 return newSFTPChannel();11 }12 /**

13 *@paramargs14 *@throwsException15 */

16 public static void main(String[] args) throwsException {17 SFTPTest test = newSFTPTest();18 Map sftpDetails = new HashMap();19 //设置主机ip,端口,用户名,密码

20 sftpDetails.put(SFTPConstants.SFTP_REQ_HOST, "10.9.167.55");21 sftpDetails.put(SFTPConstants.SFTP_REQ_USERNAME, "root");22 sftpDetails.put(SFTPConstants.SFTP_REQ_PASSWORD, "arthur");23 sftpDetails.put(SFTPConstants.SFTP_REQ_PORT, "22");24

25 String src = "D:\\DevSoft\\HB-SnagIt1001.rar"; //本地文件名

26 String dst = "/home/omc/ylong/sftp/HB-SnagIt1001.rar"; //目标文件名

27

28 SFTPChannel channel =test.getSFTPChannel();29 ChannelSftp chSftp = channel.getChannel(sftpDetails, 60000);30

31 File file = newFile(src);32 long fileSize =file.length();33

34 /**

35 * 代码段136 OutputStream out = chSftp.put(dst, new FileProgressMonitor(fileSize), ChannelSftp.OVERWRITE); // 使用OVERWRITE模式37 byte[] buff = new byte[1024 * 256]; // 设定每次传输的数据块大小为256KB38 int read;39 if (out != null) {40 System.out.println("Start to read input stream");41 InputStream is = new FileInputStream(src);42 do {43 read = is.read(buff, 0, buff.length);44 if (read > 0) {45 out.write(buff, 0, read);46 }47 out.flush();48 } while (read >= 0);49 System.out.println("input stream read done.");50 }51 **/

52

53 chSftp.put(src, dst, new FileProgressMonitor(fileSize), ChannelSftp.OVERWRITE); //代码段254

55 //chSftp.put(new FileInputStream(src), dst, new FileProgressMonitor(fileSize), ChannelSftp.OVERWRITE);//代码段3

56

57 chSftp.quit();58 channel.closeChannel();59 }60 }

SFTPTest.java

再次运行,结果输出为:

1 Try to start progress monitor.2 Progress monitor started.3 Transfering is in progress.4 Current transfered: 98019bytes5 Sending progress message: 2.55%

6 Transfering is in progress.7 Current transfered: 751479bytes8 Sending progress message: 19.53%

9 Transfering is in progress.10 Current transfered: 1078209bytes11 Sending progress message: 28.02%

12 ......13 Transfering is in progress.14 Current transfered: 3430665bytes15 Sending progress message: 89.15%

16 transfering end.17 Transfering done. Cancel timer.18 Try to stop progress monitor.19 Progress monitor stoped.

现在,程序每隔5秒钟才会打印一下进度信息。可以修改FileProgressMonitor类里的progressInterval变量的值,来修改默认的间隔时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值