Java中java.io包为咱们提供了输入流和输出流,对文件的读写基本上都依赖于这些封装好的关于流的类中来实现。前段时间遇到了如下两种需求:前端
一、与某系统对接,天天获取最新的图片并显示在前端页面。该系统提供的是一个http协议的图片URL,原本获取到该系统的图片地址之后在HTML中显示就能够了,可是该系统不太稳定,图片URL常常不能使用,并且天天生成图片不必定成功,java
对本身系统的功能影响很大,emm。。。因此就考虑天天从该系统下载最新的图片到本地更新保存,没有新图片就继续使用上次的图片。mysql
二、公司算法团队的同事完成了一个视频分析的检测功能,会生成一些截取的短视频文件,系统须要获取并保存这些视频文件。算法运行在Linux系统,没有搭建FTP服务器,因此就须要系统从运行算法的Linux系统复制文件到系统本地保存起来。算法
这两个需求实现起来都是大同小异,思路就是读取文件而后写到指定路径,只不过http协议的图片地址能够直接读取而后保存,而Linux系统的文件须要远程链接到该服务器而后再下载文件,这就须要咱们引入如下依赖:sql
<!--远程读取服务器文件--> <dependency> <groupId>ch.ethz.ganymed</groupId> <artifactId>ganymed-ssh2</artifactId> <version>262</version> </dependency> <dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.53</version> </dependency> <dependency> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> <version>3.4</version> </dependency>
废话不说了,先上代码:shell
package com.XXX.utils; import ch.ethz.ssh2.*; import com.databus.Log; import com.mysql.jdbc.StringUtils; import java.io.*; import java.net.*; public class FileUtils { /* * 根据http路径下载文件保存到指定路径 * urlString:文件路径 * fileName:保存到本地的文件名称 * filePath:本地要保存的指定路径 * */ public static boolean downloadFile(String urlString,String fileName,String filePath) { boolean bool = false; InputStream is = null; FileOutputStream os = null; try { Log.info("文件路径:" + urlString); // 构造URL java.net.URL url = new java.net.URL(urlString); // 打开链接 URLConnection con = url.openConnection(); // 输入流 is = con.getInputStream(); // 1K的数据缓冲 byte[] bs = new byte[1024]; // 读取到的数据长度 int len; //判断指定目录是否存在,不存在则先建立目录 File file = new File(filePath); if (!file.exists()) file.mkdirs(); //fileName若是不包含文件后缀,则须要加上后缀,如:fileName + ".jpg";fileName + ".txt"; os = new FileOutputStream(filePath + fileName, false);//false:覆盖文件,true:在原有文件后追加 // 开始读取 while ((len = is.read(bs)) != -1) { os.write(bs, 0, len); } bool = true; Log.info("文件保存成功:" + fileName); }catch (Exception e){ e.printStackTrace(); }finally { // 完毕,关闭全部连接 if (null != os){ try { os.flush(); os.close(); }catch (IOException e){ e.printStackTrace(); } } if (null != is){ try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } return bool; } //远程下载服务器文件 public static boolean copyFile(String ip,int port,String userName,String password,String sourceFile,String targetFile,String targetFileName){ boolean bool = false; Connection conn = null; Session session = null; try { if (StringUtils.isNullOrEmpty(ip) || StringUtils.isNullOrEmpty(userName) || StringUtils.isNullOrEmpty(password) || StringUtils.isNullOrEmpty(sourceFile) || StringUtils.isNullOrEmpty(targetFile)){ return bool; } conn = new Connection(ip,port); conn.connect(); boolean isAuth = conn.authenticateWithPassword(userName,password); if (!isAuth){ Log.info("算法主机链接失败"); return bool; } //执行命令 session = conn.openSession(); //执行命令并打印执行结果 session.execCommand("df -h"); InputStream staout = new StreamGobbler(session.getStdout()); BufferedReader br = new BufferedReader(new InputStreamReader(staout)); String line = null; while ((line = br.readLine()) != null){ System.out.println(line); } br.close(); //下载文件到本地 SCPClient scpClient = conn.createSCPClient(); SCPInputStream scpis = scpClient.get(sourceFile); //判断指定目录是否存在,不存在则先建立目录 File file = new File(targetFile); if (!file.exists()) file.mkdirs(); FileOutputStream fos = new FileOutputStream(targetFile + targetFileName); byte[] buffer = new byte[1024]; int len = 0; while ((len = scpis.read(buffer)) != -1){ fos.write(buffer,0,len); } fos.close(); bool = true; //SFTP /*SFTPv3Client sftPClient = new SFTPv3Client(conn); sftPClient.createFile(""); sftPClient.close();*/ }catch (Exception e){ e.printStackTrace(); Log.info(e.getMessage()); Log.info("保存失败:" + sourceFile); }finally { if (null != session){ session.close(); } if (null != conn) { conn.close(); } } return bool; } }
第一个方法downloadFile(String urlString,String fileName,String filePath)与咱们读写文件没什么区别,咱们主要说一下远程读取Linux服务器文件的方法:服务器
copyFile(String ip,int port,String userName,String password,String sourceFile,String targetFile,String targetFileName)
能够看到,咱们须要Linux服务器的ip、ssh开放的端口号(通常默认是22)、服务器用户名和密码,因此咱们要确保Linux服务器已经开放ssh链接,不然咱们的程序根本就连不上服务器,更不要说复制文件了。session
其实ssh2链接远程服务器,就和咱们用Xshell链接服务器是同样的,不但能够复制文件,也能够执行Linux命令对Linux进行操做,看上面的一段代码:ssh
//执行命令 session = conn.openSession(); //执行命令并打印执行结果 session.execCommand("df -h"); InputStream staout = new StreamGobbler(session.getStdout()); BufferedReader br = new BufferedReader(new InputStreamReader(staout)); String line = null; while ((line = br.readLine()) != null){ System.out.println(line); } br.close();
这段代码与复制文件没有关系,之因此保留就是要说明一下,咱们执行了df -h d 命令(查询服务器磁盘使用状况),将会获得磁盘的具体使用状况,与下图效果相同。因此咱们能够用ssh2作不少事情,有兴趣的童鞋能够多了解。url
另外在copyFile()方法的最后有一段注释的代码:
//SFTP /*SFTPv3Client sftPClient = new SFTPv3Client(conn); sftPClient.createFile("files"); sftPClient.close();*/
咱们也能够经过创建SFTP链接来远程操做目录和文件,好比:建立、删除目录,建立、删除文件等。
关于ssh2包的其余功能和用法再也不引伸,有兴趣的童鞋欢迎在评论区交流。