最近需求要求定期從一個[定期更新的文件] 中解析員工信息 ,插入到數據庫中.
按理來說很簡單, 無非就是io流讀文件,然後crud balalalala.....
其實不是的, 我我寫的這個接口 ,要實現從遠程服務器上獲取文件然後入庫操作 . . . 問題來了, 我怎麼去讀文件.
這樣就用到了linux的命令了 ,大致來說 , 從遠程服務器上獲取文件有好幾種方式 , scp快速獲取 sftp建立ssh連接 ,lftp連接 好像還有個rsync什麼的,這個沒記住 ....
大致命令爲
下載: 如果(-p端口號不好使 就替換成 -oPort=端口號)
scp -p端口號 遠程服務器用戶@遠程服務器ip:文件路徑 本地存放路徑
例子: scp -p22 [email protected]:/usr/wang.txt /usr/wang.txt 這個好像不能scp的時候改名字
sftp -p端口號 遠程服務器用戶@遠程服務器ip 建立連接之後:
get 要下載的文件路徑+文件名 本地存儲路徑
put 本地存儲路徑 要上傳的文件路徑+文件名
quit 或者exit 可以退出ssh連接
例子 懶得寫了, 直接截屏吧
lftp 這個我是和sftp 同時用的 有一個好處可以免登陸的:
現在上圖:.......
碼的公司服務器好像斷了 (掀桌!), 算了不截屏了 , 老老實實碼字吧.. . . . . . .
這個是點擊之後 , 就會進入
這個時候 cd 遠程服務器目錄 這個命令就是進入遠程服務器的目錄
lcd 本地存放目錄 這個額命令就是進入本地需要存放的目錄
get 需要下載文件名
put 需要上傳的文件名
quit或者 exit 退出
其實我要說的命令直接百度就能搜到 , 接下來就是實現自動上傳或下載了 ,大致有三種 , 我實現了有兩種 , 看這個大神的
第一種:使用lftp+sftp 命令
第二種:使用expect 命令
第三種:配置免密 看這個寫得很清楚點擊打開鏈接 大致就是使用- keygen 生成密鑰,將公鑰交給遠程服務器以配置免登錄
注意:你用那個用戶獲取的密鑰,你就要cd到那個用戶的cd /用戶名/.ssh/公鑰文件 下, 我就是用admin用戶獲取到 ,但是發現進不去/root/.ssh/ 目錄下 , 大概我是個接觸腳本兩天的小白把 ,maybe。。。。
第一種:
#!/usr/bin/bash // 這個頭部很重要
trandt=`date +%Y%m%d`
lastdt=`date -d "$trandt -2 day " +%Y%m%d`
var1=dim_user_
var2=.txt
#文件名
filename=${var1}${lastdt}${var2} /需求上說的是文件名跟日期變動的,所以我的文件名這麼寫 , 可以寫死的!
USER=wodemingzi
#密碼
PASSWORD=wodemima
#下載文件目錄
#LOCAL=/usr/local/src/ 文件admin沒有讀寫權限
LOCAL=/home/admin/ // 儘量放在這個目錄下吧 有的應用沒有其他文件夾的讀寫權限
#FTP目錄(待下載文件目錄)
REMOTE=/jd_tfm_file/
#銀聯IP
IP=10.10.10.168
#端口
PORT=2374
lftp -u ${USER},${PASSWORD} sftp://${IP}:${PORT}<<EOF
cd ${REMOTE}
lcd ${LOCAL}
#需要下載的文件
get ${filename}
EOF
這個腳本其實不算難 , 但是實現的時候非常的艱難 , 首先是腳本不能執行的問題 , 需要注意的地方我加粗了 這個文件的名字爲lftp.sh
是個shell腳本文件, 需要 是sh lftp.sh 來運行的 .
其次就是文件不能執行的問題:
文件權限需要用 chmod 777 腳本文件.sh 獲取權限
+++++++++++++++++++++++++++今天先寫到這, 明天再寫吧++++++++++++++++++++++++++++++++
繼續寫:
文件獲取權限之後 ,使用sh lftp.sh就可以執行了
但是有一個問題, 看貼圖吧
我使用cat命令,把腳本粘貼到命令行執行,
wht?!!!沒有報告任何錯誤 , 直接就把遠程服務器文件get到了我本地指定目錄裏面。
錯誤.jpg
假裝有圖,
發現執行到, 這裏 , 就不執行了 , 始終搞不懂到底是爲啥 , 百度了各大資料, 有人說 這是lftp命令沒裝好, 有人說這是沒有指定目錄, 還有人用./wang.sh 的方式 ,還有人說是用戶權限的問題 , 我把代碼粘出來就能執行你告訴我是權限的問題??!!!
總之全他麼的不好使 ,最後本人媳婦(大神)告訴我 ,你這個文件的聲明不對吧,,,shell腳本聲明頭應該是這樣的
#!/usr/bin/bash
看到我之前發的截圖嗎 , 頭部明顯不太對 , 好吧, 然後我就改了 ,然後繼續用
sh wang.sh ;
發現還是不好使 ; 報的錯不粘出來了 , 這次是真的沒辦法了, 我就放棄了一段時間 ,然後幹別的去了......
=======n小時後, 我又開始驗證這段腳本 了, 不好使 , 不知道怎麼回事,我進入了這個大神的博客 , 我其實不想驗證的,因爲我一開始就害怕腳本是dos格式的 ,我就全刪了,然後在linux中手打了一遍的......
反正閒的蛋疼, 我就用
vi wang.sh
按Esc , 輸入 冒號 ff見下面
: set ff ===>>> 得到的他麼的竟然是 'dos' , !!!!!!!!!!!這回真的是傷了
先弄好了吧 , 輸入 冒號 set ff=unix
: set ff=unix ,==>>>>再輸入 :set ff 發現就變成 unix 了 .
好這次我繼續敲:
sh wang.sh ; ^_^,終於成功了!!!!
第一種方式完成!!!!!
總結: 腳本
第一要先驗證腳本格式是什麼類型的,是dos 還是unix 的 ,這個很重要 鏈接在這裏
https://blog.csdn.net/chengxuyuanyonghu/article/details/47340123
第二,一定要注意頭部一定要正確, 確保你的命令在linux中已經安裝了
第三,確保你的腳本文件時一個可執行的文件 , 不可執行,使用 chmod 777 文件名 獲取權限
第四:這個我最後遇到了, 不過懶得再複述了. , 在你的腳本中設置 本地存放路徑(lcd 路徑) 的時候 ,一定要確保你的當前用戶(不管是root還是 admin還是其他) 是擁有這個目錄的讀寫權限的,這個存放目錄建議就放在/home/用戶名/ 這個目錄下最靠譜.
第五: 沒了.(對了,就算做到了這些, 也要確保遠程服務器和本地服務器的連通性 ,先使用單行命令,是不是能連通 ,然後再去測腳本)
============================o(╥﹏╥)o=============================
第二種方式: 使用expect 命令的方式 ,
很不幸, 我的這個不好使 , 一直報告找不到
spawn not found
我確實安裝了 expect 命令
貼一下代碼吧
沒辦法 , 我試了上述那幾個總結, 依舊不好使
希望你們能發現是什麼問題:
首先使用命令安裝了expect 我使用 exp expect.exp 也跑不動這個腳本.
總之這個就棄用了.
============================o(╥﹏╥)o=============================
第三種方式: 配公鑰
也是最方便的最快捷的方式 配置公鑰的方式,配置完了可以直接使用scp 命令 ,sftp 命令 ,lftp 命令 一行就把文件neng過來!
上面寫過鏈接了, 再發一遍點擊打開鏈接
寫的很清楚了, 使用
ssh-keygen ===>>然後一路回車 ,
會生成一個小圖片 ,圈圈點點之類的 , 同時會在你的 /home/用戶名/.ssh/ 家目錄下生成 公鑰和私鑰,
私鑰文件(id_rsa)和公鑰文件(id_rsa.pub) 公鑰文件 使用 cat id_rsa.pub 命令
打開 , 將裏面的內容複製到===>>>>遠程服務器下同級目錄下的authorized_keys(沒有這個文件就創建一個就行) 中,多行要回車 隔開.
直接拿大神截圖過來用了,參考下......-_-||(公司又斷網了)
直接用scp -p22 [email protected]:/export/123.txt /home/root/123.txt 可以拉取到我本地
用 sftp -oPort(同一公司內服務器用-p就行)=22 [email protected] , 可以直接連接上 不需要輸入密碼了;
然後 cd /export/ ===>>>到遠程目錄下
cd /home/root/ ===>>>到本地目錄下
get 文件名 ===>>>妥妥的複製過來了(put也一樣)
lftp 上面寫過了.
把java代碼也粘一下.(目前還不想使用github,因爲比較菜 ,不想過多把精力放在這上面 ,文章也懶得排版,想到哪就寫到哪了.....有問題加我球球號952288306 交流)
執行腳本的java代碼:
package com.jd.ecc.tianfu.tools;
import com.jd.ecc.tianfu.utils.FileUtils;
import java.io.*;
/**
*
* @author wangwenbin1
* 執行腳本的工具類
*/
public class JavaLinuxManager {
public String Linuxscp(String img,String encode){
String msg = null;
try {
Process ps = Runtime.getRuntime().exec(img);
ps.waitFor();
msg = loadStream(ps.getErrorStream(),encode);
System.err.print(msg);
ps.destroy();
} catch (Exception e) {
e.printStackTrace();
}
return msg;
}
static String loadStream(InputStream in,String encode) throws IOException {
//把所有的數據讀取到這個字節當中
byte[] b = new byte[1024];
//聲明一個int存儲每次讀取到的數據
int i = 0;
//定義一個記錄索引的變量
int index = 0;
//循環讀取每個數據
while((i=in.read())!=-1) {//把讀取的數據放到i中
b[index] = (byte) i;
index++;
}
return new String(b,encode==null?"utf-8":"gbk");
}
// public static void main(String[] args) throws Exception {
// File file = new File("d:a.txt");
// FileInputStream fileIn = new FileInputStream(file);
// String s = loadStream(fileIn, FileUtils.encoded(file));
// System.out.println(s);
// }
}
controller很簡單, 就是 不少註解是swagger的 可以忽略 ,主要看加粗的部分
@ApiOperation(value = "執行java腳本") @RequestMapping(value = "/runtime/img", produces = "application/json;charset=utf-8") public RespData<Map<String, Object>> img( @ApiParam(value = "平臺ID", required = true) @RequestParam("platformId") Long platformId, @ApiParam(value = "腳本或者文件路徑(chmod 777 ./WEB-INF/shs/sftp.sh)", required = true) @RequestParam("img") String img, HttpServletRequest request, @ApiParam(value = "驗證碼", required=true) @RequestParam(value = "authcode",required = true)String authcode) { try { // chmod 777 ./WEB-INF/shs/sftp.sh if ("XXX一個驗證碼省得別人惡意拼接XXXXX".equals(authcode)){ JavaLinuxManager unix = new JavaLinuxManager(); String linuxscp = unix.Linuxscp(img, null); Map<String,Object> map = new HashMap<>(); map.put("msg",linuxscp); return RespData.success(map); }else { return RespData.error("0000","驗證碼失敗!!!"); } } catch (Exception e) { LOG.error("執行異常!", e); e.printStackTrace(); } return RespData.error("0000", "執行異常"); }
附一個文件工具類:
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; /** * 讀取文本工具類 * @author wangwenbin1 * */ public class FileUtils { private static final Logger LOG = org.slf4j.LoggerFactory.getLogger(FileUtils.class); /** * 判斷文件是否存在 不存在創建空文件 * @param file * @return * @throws IOException */ public static boolean isExistFile(File file) throws IOException { // 判斷是否存在 if (file.exists()) { // 判讀是否是一個文件 return file.isFile(); } else if (file.length() == 0) { LOG.info("文件內容爲空"); } else { LOG.info("文件不存在!"); } return false; } /** * 判斷文件的編碼方式 * @param file * @return * @throws IOException */ public static String encoded(File file) throws IOException{ InputStream in = new FileInputStream(file); byte[] b = new byte[3]; in.read(b); in.close(); if (b[0]==-17&&b[1]==-69&&b[2]==-65) { // 一般來說,utf-8 的前三個字符爲上述三個 LOG.info("文件utf-8編碼!"); return "utf-8"; }else{ LOG.info("文件gbk編碼!"); return "gbk"; } } /** * 讀取txt文件 返回Sting * @param path * @return * @throws IOException */ public static String readTXTFile(String path) throws IOException { File file = new File(path); boolean existFile = isExistFile(file); if (existFile) { LOG.info("文件存在且內容非空!"); String charset = encoded(file); InputStreamReader reader = new InputStreamReader(new FileInputStream(file), charset); BufferedReader bf = new BufferedReader(reader); StringBuffer sb = new StringBuffer(); String text = ""; while ((text = bf.readLine()) != null) { sb.append(text); sb.append(";"); //sb.append("\r\n"); } String sbNew = sb.substring(0, sb.length() - 1); reader.close(); bf.close(); return sbNew; } return ""; } }