Java中java.io包为我们提供了输入流和输出流,对文件的读写基本上都依赖于这些封装好的关于流的类中来实现。前段时间遇到了以下两种需求:

  1、与某系统对接,每天获取最新的图片并显示在前端页面。该系统提供的是一个http协议的图片URL,本来获取到该系统的图片地址以后在HTML中显示就可以了,但是该系统不太稳定,图片URL经常不能使用,而且每天生成图片不一定成功,

对自己系统的功能影响很大,emm。。。所以就考虑每天从该系统下载最新的图片到本地更新保存,没有新图片就继续使用上次的图片。

  2、公司算法团队的同事完成了一个视频分析的检测功能,会生成一些截取的短视频文件,系统需要获取并保存这些视频文件。算法运行在Linux系统,没有搭建FTP服务器,所以就需要系统从运行算法的Linux系统复制文件到系统本地保存起来。

  这两个需求实现起来都是大同小异,思路就是读取文件然后写到指定路径,只不过http协议的图片地址可以直接读取然后保存,而Linux系统的文件需要远程连接到该服务器然后再下载文件,这就需要我们引入以下依赖:

<!--远程读取服务器文件-->
<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>

  废话不说了,先上代码:

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连接,否则我们的程序根本就连不上服务器,更不要说复制文件了。

  其实ssh2连接远程服务器,就和我们用Xshell连接服务器是一样的,不但可以复制文件,也可以执行Linux命令对Linux进行操作,看上面的一段代码:

//执行命令
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做很多事情,有兴趣的童鞋可以多了解。

  另外在copyFile()方法的最后有一段注释的代码:

//SFTP
/*SFTPv3Client sftPClient = new SFTPv3Client(conn);
sftPClient.createFile("files");
sftPClient.close();*/

  我们也可以通过建立SFTP连接来远程操作目录和文件,比如:创建、删除目录,创建、删除文件等。

  关于ssh2包的其他功能和用法不再引申,有兴趣的童鞋欢迎在评论区交流。

Java远程下载文件到本地(http协议和ssh2协议)的更多相关文章

  1. java远程下载文件到本地

    方法一 ** * 下载远程文件并保存到本地 * * @param remoteFilePath-远程文件路径 * @param localFilePath-本地文件路径(带文件名) */ public ...

  2. PHP实现远程下载文件到本地

    PHP实现远程下载文件到本地 投稿:hebedich 字体:[增加 减小] 类型:转载   经常写采集器发布接口需要使用到远程附件的功能,所以自己写了一个PHP远程下载文件到本地的函数,一般情况下已经 ...

  3. PHP CURL实现远程下载文件到本地

    <?php //$result=httpcopy('http://www.phpernote.com/image/logo.gif'); echo '<pre>';print_r($ ...

  4. java实现下载文件到本地

    代码如下: URL url = new URL("http://www.cnblogs.com/images/logo_small.gif"); URLConnection con ...

  5. 使用xshell从远程服务器下载文件到本地

    XSHELL工具上传文件到Linux以及下载文件到本地(Windows) Xshell很好用,然后有时候想在windows和linux上传或下载某个文件,其实有个很简单的方法就是rz,sz.首先你的L ...

  6. 在Xshell中上传下载文件到本地(linux中从多次ssh登录的dbserver里面的文件夹)

    在Xshell中上传下载文件到本地(linux中从多次ssh登录的dbserver里面的文件夹) 1 列出所有需要copy的sh文件 -bash-4.1$ ll /mysqllog/osw/*.sh ...

  7. C#使用WebClient下载文件到本地目录

    C#使用WebClient下载文件到本地目录. 1.配置本地目录路径 <appSettings> <!--文件下载目录--> <add key="Downloa ...

  8. Js点击按钮下载文件到本地(兼容多浏览器)

    实现点击 用纯 js(非jquery)  下载文件到本地 自己尝试,加网上找了好久未果,如: window.open(url)   location.href=url   form表单提交   ifr ...

  9. 【转】XSHELL下直接下载文件到本地(Windows)

    XSHELL下直接下载文件到本地(Windows) http://www.cnblogs.com/davytitan/p/3966606.html

随机推荐

  1. UOJ61. 【UR #5】怎样更有力气

    题目链接 Statement 给定一棵 \(n\) 点树 \(T\) 和 \(m\) 个操作 v u w : 在 \(T\) 中 \(u,v\) 的最短路上所有点里面选出若干对(可以不选,可以重复), ...

  2. Codeforces Edu Round 65 A-E

    A. Telephone Number 跟之前有一道必胜策略是一样的,\(n - 10\)位之前的数存在\(8\)即可. #include <iostream> #include < ...

  3. Vue-组件传值:子传父和兄弟组件间常见的传值方式

    前言 上篇介绍了我对vue组件化的理解和父组件对子组件传值的方式,这篇介绍下常见的子传父和兄弟组件间的传值方式 目录 子组件向父组件传值 任意组件间的传值方式 正文 子组件向父组件传值 关键知识点:$ ...

  4. idea 最好用的插件

    1.lombok 不用写get,set方法 2.MyBatisCodeHelperPro 3.Rainbow Brackets 彩虹括号 5.activate-power-mode 动感打字 7.Ba ...

  5. RabbitMQException com.rabbitmq.client.ShutdownSignalException: connection error; protocol meth

    异常1 org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ...

  6. 6 个例子教你重构 Python 代码

    1. 合并嵌套的 if 条件 太多的嵌套会使代码难以理解,这在 Python 中尤为如此,因为 Python 没有括号来帮助区隔不同的嵌套级别. 阅读深度嵌套的代码容易让人烦躁,因为你必须理清哪些条件 ...

  7. .NET Core 使用MediatR CQRS模式 读写分离

    前言 CQRS(Command Query Responsibility Segregation)命令查询职责分离模式,它主要从我们业务系统中进行分离出我们(Command 增.删.改)和(Query ...

  8. C# 多态virtual标记重写 以及EF6 查询性能AsNoTracking

    首先你如果不用baivirtual重写的话,系统默认会为du你加new关键字,他zhi的作用是覆盖,而virtual的关键作用在dao于实现多态 virtual 代表在继承了这个类的子类里面可以使用o ...

  9. 个人MySQL的事务特性原理学习笔记总结

    目录 个人MySQL的事务特性原理笔记总结 一.基础概念 2. 事务控制语句 3. 事务特性 二.原子性 1. 原子性定义 2. 实现 三.持久性 1. 定义 2. 实现 3. redo log存在的 ...

  10. 记一次Apache的代码导致生产服务耗时增加

    引言 二狗:二胖快醒醒,赶紧看看刚才报警邮件,你上次写的保存用户接口耗时(<二胖的参数校验坎坷之路>)大大上升,赶紧排查下原因. 二胖:好的,马上看,内心戏可十足(心里却在抱怨,大中午的搅 ...