在這篇文中要展示如何用 Java 以 JSch 這個 library 來進行 SSH 連線,
首先是用 Maven 引入 library :
<!-- https://mvnrepository.com/artifact/com.jcraft/jsch --> <dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.55</version> </dependency>接著先直接上程式碼:
package test;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;
public class SftpTest {
public static void main(String[] args) throws Exception {
String privateKeyPath = "D:\\...\xx.pem"; //your private key file path
String userName = "xxName"; //your username to access target server
String host = "xxx.xxx.xxx.xxx"; //hostname of target server
int port = 22; //target server port
Session session = null;
try (InputStream inputStreamOfPrivateKey = new FileInputStream(new File(privateKeyPath))){
JSch jsch = new JSch();
jsch.addIdentity(privateKeyPath, inputStreamOfPrivateKey.readAllBytes(), null, null);
session = jsch.getSession(userName, host, port);
//session.setPassword("xxxPassword");
session.setConfig("StrictHostKeyChecking", "no");
session.setTimeout(60000);
session.connect();
ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect();
//check if file exists
System.out.println(isFileExist(channelSftp, "/xxx/xxx.png"));
//check file attributes
SftpATTRS fileAttrs = channelSftp.lstat("/xxx/xxx.png");
System.out.println(fileAttrs.getSize());
//create directory
mkdir(channelSftp, "/xxx/xxx");
//upload file
upload(channelSftp, "D:\\xxx\\xxx.jpg", "/xxx/xxx");
channelSftp.exit();
}catch(Exception e) {
e.printStackTrace();
} finally {
if (session != null && session.isConnected()) {
session.disconnect();
}
}
System.out.println("Done");
}
public static void upload(ChannelSftp channelSftp, String srcFilePath, String targetDirectoryPath) {
targetDirectoryPath = targetDirectoryPath.replace("\\", "/");
File srcFile = new File(srcFilePath);
try (FileInputStream fileInputStream = new FileInputStream(srcFile)){
if (isFileExist(channelSftp, targetDirectoryPath)) {
channelSftp.cd(targetDirectoryPath);
}else {
channelSftp.cd("/"); //go to root path
String[] targetDirectoryNameList = targetDirectoryPath.split("/");
for(String targetDirectoryName : targetDirectoryNameList) {
if ("".equals(targetDirectoryName)) {
continue;
}
if (!isFileExist(channelSftp, targetDirectoryName)) {
channelSftp.mkdir(targetDirectoryName);
}
channelSftp.cd(targetDirectoryName);
}
}
channelSftp.put(fileInputStream, srcFile.getName());
} catch (IOException | SftpException e) {
e.printStackTrace();
}
}
static void mkdir(ChannelSftp channelSftp, String directoryPath) {
directoryPath = directoryPath.replace("\\", "/");
try {
channelSftp.cd("/"); //go to root path
String[] directoryNameList = directoryPath.split("/");
for(String directoryName : directoryNameList) {
if ("".equals(directoryName)) {
continue;
}
if (!isFileExist(channelSftp, directoryName)) {
channelSftp.mkdir(directoryName);
}
channelSftp.cd(directoryName);
}
} catch (SftpException e) {
e.printStackTrace();
}
}
static boolean isFileExist(ChannelSftp channelSftp, String filePath) {
boolean isFileExist = false;
try {
channelSftp.lstat(filePath);
isFileExist = true;
} catch (SftpException e) {
if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
isFileExist = false;
}
}
return isFileExist;
}
}
說明:上面程式碼的情境是想要 SSH 連線至一台 Linux Server,
且已經設定好 ssh public key 並放在 server 的 .ssh 資料夾裡,
而我們本地的機器上也已經有一個對應的 ssh private key,
所以我們只需使用 private key 來進行連線而不用使用密碼。
session.setConfig("StrictHostKeyChecking", "no");
這行程式碼設定了 StrictHostKeyChecking 為 no,
是因為在 SSH 連線時有時會需要終端機互動,
例如在使用命令式模式指令進行 SSH 連線操作時,
server 可能會跳出一些訊息要你輸入 "yes" 等動作才能進行下一步,
設定 StrictHostKeyChecking 為 no 就可以避免這種互動式操作,
可參考:
在程式碼中可以看到,取得了 ChannelSftp 實例後,
就可以使用它來進行對 server 的操作,例如: cd, pwd, ls, mkdir, ... 等,
就像我們平台用命令列模式指令一樣,當使用了 cd 指令後,
會把我們帶到特定的 server 上的檔案路徑位置,
並且可以以目前所在的位置用相對路徑進行 ls, mkdir, ... 等操作,
當然也可使用絕對路徑進行操作。
在上述程式碼中,
我包裝並實作了 isFileExist(), upload(), mkdir() 等 methild
來取代直接使用 ChannelSftp 自身的 API,
在實作的 method 中限定了檔案路徑參數必須為絕對路徑以避免不必要的
路徑處理麻煩,
isFileExist() 使用了 ChannelSftp.lstat() 和 ChannelSftp.SSH_FX_NO_SUCH_FILE 的補獲來實作。
upload() 和 mkdir() 使用 isFileExist() 來判斷路徑上資料夾的存在與否,
如果不存在的話則幫忙建立相應的資料夾。
沒有留言 :
張貼留言