java 通過shell命令來操作服務器上的文件,實現複製、編輯內容等。

備註:根據自己的業務可以去修改一下。下面只是實現了我的業務:將服務器上的文件複製到另一個文件下,並且在指定的內容處添加內容。

1.pom文件

      <!-- https://mvnrepository.com/artifact/com.jcraft/jsch -->
      <dependency>
          <groupId>com.jcraft</groupId>
          <artifactId>jsch</artifactId>
          <version>0.1.55</version>
      </dependency>

      <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
      </dependency>

      <!-- https://mvnrepository.com/artifact/ch.ethz.ganymed/ganymed-ssh2 -->
      <dependency>
          <groupId>ch.ethz.ganymed</groupId>
          <artifactId>ganymed-ssh2</artifactId>
          <version>262</version>
      </dependency>

      <dependency>
          <groupId>ch.ethz.ganymed</groupId>
          <artifactId>ganymed-ssh2</artifactId>
          <version>build210</version>
      </dependency>

2.

package com.ed.core.util;

import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.SFTPv3Client;
import ch.ethz.ssh2.SFTPv3DirectoryEntry;
import ch.ethz.ssh2.StreamGobbler;
import com.jcraft.jsch.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

/**
 * @ProjectName: gitIdeaWork
 * @Package: com.ed.core.util
 * @ClassName: DestHostShell
 * @Author: zhao
 * @Description:
 * @Date: 2019/12/23 18:18
 * @Version: 1.0
 */
public class DestHostShell {
    Logger logger = LoggerFactory.getLogger(DestHostShell.class);

    private static String userName = "***";
    private static String password = "***";
    private static String host = "***.***.*.**";
    private static Integer port = 22;

    /**
     * 文件複製
     * cpCommand : cp /home/upload/hello.txt /home/include/
     * @param cpCommand
     * @return
     * @throws IOException
     * @throws JSchException
     */
    public static void execCommandByShell(String cpCommand)throws IOException,JSchException{

        JSch jsch = new JSch();
        Session session = null;
        try {
            session = jsch.getSession(userName, host, port);
            session.setPassword(password);
            session.setConfig("StrictHostKeyChecking", "no");//第一次訪問服務器不用輸入yes
            session.setTimeout(60*60*1000);
            session.connect();

            //2.嘗試解決 遠程ssh只能執行一句命令的情況
            ChannelShell channelShell = (ChannelShell) session.openChannel("shell");
            InputStream inputStream = channelShell.getInputStream();//從遠端到達的數據  都能從這個流讀取到
            channelShell.setPty(true);
            channelShell.connect();

            OutputStream outputStream = channelShell.getOutputStream();//寫入該流的數據  都將發送到遠程端
            //使用PrintWriter 就是爲了使用println 這個方法
            //好處就是不需要每次手動給字符加\n
            PrintWriter printWriter = new PrintWriter(outputStream);
            printWriter.println(cpCommand);
            printWriter.println("exit");//爲了結束本次交互
            printWriter.flush();//把緩衝區的數據強行輸出

            /**
             shell管道本身就是交互模式的。要想停止,有兩種方式:
             一、人爲的發送一個exit命令,告訴程序本次交互結束
             二、使用字節流中的available方法,來獲取數據的總大小,然後循環去讀。
             爲了避免阻塞
             */
            byte[] tmp = new byte[1024];
            while(true){
                while(inputStream.available() > 0){
                    int i = inputStream.read(tmp, 0, 1024);
                    if(i < 0) break;
                    String s = new String(tmp, 0, i);
                    if(s.indexOf("--More--") >= 0){
                        outputStream.write((" ").getBytes());
                        outputStream.flush();
                    }
                    System.out.println(s);
                }
                if(channelShell.isClosed()){
                    System.out.println("退出狀態"+channelShell.getExitStatus());
                    break;
                }
                try{Thread.sleep(1000);}catch(Exception e){}
            }
            outputStream.close();
            inputStream.close();
            channelShell.disconnect();
            session.disconnect();
            System.out.println("複製完成");
        } catch (JSchException e) {
            e.printStackTrace();
        }
    }

    /**
     * 文件內容讀取拼接
     * @param directory:/home/testc/include/
     * @param findContent : 指定內容
     * @param replaceContent    替換內容
     * @return
     */
    public static String fileReadStr(String directory,String findContent,List<String> replaceContent,String fileName,String path){
        //聲明連接對象
        Connection conn = null;
        ch.ethz.ssh2.Session ss=null;
        //參數
        List<String> fileNameList=new ArrayList<String>();  //存放文件名
        try {
            //連接遠程服務器
            // 連接部署服務器
            conn = new Connection(host);
            conn.connect();
            //使用用戶名和密碼登錄
            boolean b = conn.authenticateWithPassword(userName, password);
            if (!b) {
                throw new IOException("身份驗證失敗!");
            } else {
                SFTPv3Client sft = new SFTPv3Client(conn);
                Vector<?> v = sft.ls(directory);//日誌文件存放的目錄
                //遍歷該目錄下的所有文件
                for (int i = 0; i < v.size(); i++) {
                    SFTPv3DirectoryEntry s = new SFTPv3DirectoryEntry();
                    s = (SFTPv3DirectoryEntry) v.get(i);
                    //文件名
                    String filename = s.filename;
                    if (filename.length() > 0 && filename.equals(fileName)) {
                        //獲取符合要求的文件名
                        System.out.println("符合條件的文件名 - >"+filename);
                        fileNameList.add(filename);
                    }
                }

                List<String> contentList = new ArrayList<>();

                //讀取文件內容,並複製給UserInfo對象
                for (int j = 0; j<fileNameList.size() ; j++) {
                    ss=conn.openSession();  //打開會話
                    ss.execCommand("cat ".concat(directory+fileNameList.get(j)));  //讀取對應目錄下的對應文件
                    InputStream    is = new StreamGobbler(ss.getStdout());
                    InputStreamReader gbk = new InputStreamReader(is, "UTF-8");
                    BufferedReader bs = new BufferedReader(gbk);  //防止中文亂碼
                    int lineCount = 0;
                    while(true){
                        String line=bs.readLine();
                        if(line==null){
                            break;
                        }else{
                            contentList.add(line);
                            lineCount++;
                            System.out.println( "第" + lineCount + "行,內容爲:" + line);
                            //不等於#號,原因是防止這行註釋掉
                            if(line.indexOf(findContent) != -1 && line.indexOf("#") == -1){
                                for(int i = 0; i < replaceContent.size(); i++){
                                    contentList.add(replaceContent.get(i));
                                }
                            }
                        }
                    }
                    bs.close();
                }
                ss.close();
                conn.close();

                upLoadToIgenetech(contentList,fileName,path);
            }
        } catch (IOException e) {
            System.err.printf("用戶%s密碼%s登錄服務器%s失敗!", userName, password, host);
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 文件內容編輯
     * @param contentList   :內容
     * @param fileName  :文件名稱
     * @param dPath : /home/include/
     */
    public static void upLoadToIgenetech(List<String> contentList, String fileName, String dPath){
        JSch jsch = new JSch();
        Session session = null;
        try {
            //用戶名、ip地址、端口號
            session = jsch.getSession(userName, host, port);
        } catch (JSchException e) {
            e.printStackTrace();
        }
        // 設置登陸主機的密碼
        session.setPassword(password);// 設置密碼
        // 設置第一次登陸的時候提示,可選值:(ask | yes | no)
        session.setConfig("StrictHostKeyChecking", "no");
        // 設置登陸超時時間
        try {
            session.connect(300000);
        } catch (JSchException e) {
            e.printStackTrace();
        }
        Channel channel = null;
        try {
            channel = (Channel) session.openChannel("sftp");
            channel.connect(10000000);
            ChannelSftp sftp = (ChannelSftp) channel;
            try {
                sftp.cd(dPath);
            } catch (SftpException e) {
                sftp.mkdir(dPath);
                sftp.cd(dPath);
            }
            OutputStream o = null;
            File file = new File(dPath + "/" + fileName);
            o = sftp.put(file.getName());
            new File(dPath + "/" + fileName);
            for(int i = 0; i < contentList.size(); i++){
                o.write((contentList.get(i) + "\r\n").getBytes("UTF-8"));
            }
            o.close();

            System.out.println("編輯完成!");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            session.disconnect();
            channel.disconnect();
        }
    }
}

3.本地測試好使,部署在服務器上,立馬不行,開始報錯。各種百度好多坑,終於找到了解決辦法
發現是由於JRE缺少包導致,添加包解決:
sunjce_provider.jar
位於本地JRE目錄jre/lib/ext/下
將上面那個包複製到你自己項目的下面就ok。

 JSchException: Session.connect: java.security.NoSuchAlgorithmException: DH KeyPairGenerator not avai

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章