前言
项目中需要从一台服务器调取其他Linux服务器上的文件,并上传到其他服务器接口中;用的是通过文件流上传;
主要是用的: session.execCommand(str) 和session.getStdout() 来获取读取到的文件流;
开始一直读取不到文件的实际大小,一直是0字节;
后来在两个方法之间加了休眠,但实际运行中,还有部分文件没有获取到实际大小,还是0字节;
再后来又优化了一下,应该是都读取成功了。
如果读取的文件过大、或者网络不好,建议加大休眠时间试试。
---------------------------------------------------------2020.06.09优化-----------------------------------------------------------
程序运行了数周后,对接方有反馈文件大小不一致,经排查,好像最终上传时文件流中的大小还不是实际文件的大小,可能只读取了一部分就开始上传了;
优化后的方案是:先执行命令获取文件大小,再用命令获取文件流,对比文件的大小还流的大小,一致时再往下执行。
一、依赖
<dependency>
<groupId>com.trilead</groupId>
<artifactId>trilead-ssh2</artifactId>
<version>1.0.0-build222</version>
</dependency>
二、代码
/**
* 获取conn
* @param ip
* @param port
* @param user
* @param pwd
* @return
*/
private static Connection getConn(String ip, int port, String user, String pwd) {
Connection conn = new Connection(ip, port);
if(conn.isAuthenticationComplete()) {
return conn;
}
try {
conn.connect();
boolean isAuthenticated = conn.authenticateWithPassword(user, pwd);
if(!isAuthenticated) {
throw new BaseException("authentication failed!");
}
return conn;
} catch (Exception e) {
log.error("Connect error:", e);
e.printStackTrace();
}
return null;
}
/**
* 获取session
* @param conn
* @return
* @throws IOException
*/
public static Session getSession(Connection conn) throws IOException{
Session session = conn.openSession();
return session;
}
/**
* 获取SFTPv3Client
* @param conn
* @return
* @throws IOException
*/
public static SFTPv3Client getClient(Connection conn) throws IOException {
SFTPv3Client client = new SFTPv3Client(conn);
return client;
}
1.主要方法:
/**
* 读取远端文件流
* @param filePath
* @return
* @throws IOException
*/
private static InputStream readFile(Connection conn, String filePath, String ip) throws IOException, InterruptedException {
Session session = getSession(conn);
//获取文件大小
session.execCommand("du -b ".concat(filePath));
InputStream sizeIn = new StreamGobbler(session.getStdout());
//将字节流向字符流的转换。
InputStreamReader isr = new InputStreamReader(sizeIn);//读取
//创建字符流缓冲区
BufferedReader bufr = new BufferedReader(isr);//缓冲
String line;
int fileSize = 0;
while((line = bufr.readLine())!=null){
String[] fileAttr = line.split("\t");
fileSize = Integer.parseInt(fileAttr[0]);
}
isr.close();
session.close();
log.info(" 【" + ip + "】【文件大小】" + fileSize);
session = getSession(conn);
session.execCommand("cat ".concat(filePath));
//休眠2秒再获取返回信息,防止网络传输过程中延迟造成读取文件大小为0字节
//Thread.sleep(2000);
InputStream is = new StreamGobbler(session.getStdout());
session.waitForCondition(ChannelCondition.EXIT_STATUS, TIME_OUT);
//获取指令是否成功执行:0-成功,非0-失败.
//int ret = session.getExitStatus();
//log.info(" 【" + ip + "】【命令执行结果】" + (0 == ret ? "---成功---" : "====失败===="));
log.info(" 【" + ip + "】【获取到当前文件流为】" + is.available());
int i = 0;
while (fileSize != is.available()) {
i++;
Thread.sleep(1000);
log.info(" 【" + ip + "】【第" + i + "次获取到当前文件流为】" + is.available());
}
session.close();
return is;
}
2.其他方法:
/**
* 判断远程服务器路径是否是目录
* @param client
* @param path
* @return
*/
private static boolean isDirectory(SFTPv3Client client, String path) {
try {
SFTPv3FileAttributes attributes = client.stat(path);
return attributes.isDirectory();
} catch(IOException e) {
log.error("获取文件属性异常", e);
}
return false;
}