挖掘機(DMS)(伺服器與客戶端讀寫檔案,收發資料)
Client
package com.company;
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.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.company.bo.LogData;
import com.company.bo.LogRec;
import com.company.util.IOUtil;
/**
* 客戶端應用程式:
* 執行在unix系統上,作用是定期讀取系統日誌檔案wtmpx檔案,
* 收集每個使用者的登入登出日誌,將匹配成對的日誌資訊傳送至伺服器
*/
public class Client {
//UNIX系統日誌檔案wtmpx檔案
private File logFile;
//儲存解析後的日孩子檔案
private File textLogFile;
//儲存每次解析日誌檔案後的位置(書籤)的檔案
private File lastPositionFile;
//每次從wtmpx檔案中解析日誌的條數
private int batch;
//儲存每次配對完畢後的所有配對日誌的檔案
private File logRecFile;
//儲存每次配對後,沒有配對成功的登入日誌的檔案
private File loginFile;
/**
* 構造方法初始化
*/
public Client(){
try {
this.batch = 10;
logFile = new File("wtmpx");
lastPositionFile = new File("last-position.txt");
textLogFile = new File("log.txt");
logRecFile = new File("logrec.txt");
loginFile = new File("login.txt");
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* 該方法為第一大步第二小步的邏輯
* 用於檢查wtmpx檔案是否還有資料可讀
* @return -1:沒有資料可讀了
* 其他數字:繼續讀取的位置
*/
public long hasLogs(){
try {
//預設從檔案開始讀取
long lastposition = 0;
/*
* 這裡有兩種情況
* 1:沒有找到last-position.txt
* 檔案,這說明從來沒讀過wtmpx
* 2:有last-position.txt檔案,
* 那麼,那麼就從檔案記錄的位置開始讀取
*/
if(lastPositionFile.exists()){
lastposition = IOUtil.readLong(lastPositionFile);
}
/*
* 必要判斷,wtmpx檔案的總大小
* 減去這次準備開始讀取的位置,應當
* 大於一條日誌所佔用的位元組量(372)
*/
if(logFile.length()-lastposition < LogData.LOG_LENGTH){
lastposition = -1;
}
return lastposition;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* 當前RandomAccessFile讀取的位置
* 在logfile中是否還有內容可讀
*/
public boolean hasLogsByStep(RandomAccessFile raf) throws IOException{
if(logFile.length()-raf.getFilePointer()>LogData.LOG_LENGTH){
return true;
}else{
return false;
}
}
/**
* 第一大步:
* 從wtmpx檔案中一次讀取batch條日誌,並解析為batch條字串,
* 每行字串表示一條日誌,然後寫入log.txt檔案中
*
* return true:解析成功
* return false:解析失敗
*/
public boolean readNextLogs(){
/*
* 解析步驟:
* 1:先判斷wtmpx檔案是否存在
* 2:判斷是否有新資料可讀
* 3:從上次讀取的位置繼續開始讀取
* 4:迴圈batch次,讀取batch個372位元組,並轉換為batch個日誌
* 5:將解析後的batch個日誌寫入log.txt檔案中
*/
//1:先判斷wtmpx檔案是否存在
if(!logFile.exists()){
return false;
}
//2:判斷是否有新資料可讀
long lastposition = hasLogs();
if(lastposition<0){
return false;
}
/*
* 為了避免重複執行第一步,而導致原來第一步中已經解析的日誌檔案被廢棄,
* 我們可以先判斷:若第一步執行完畢後生成的log.txt檔案存在,就不再執行第一步了。
* 該檔案會在第二步執行完畢後刪除。
*/
if(textLogFile.exists()){
return true;
}
try{
RandomAccessFile raf = new RandomAccessFile(logFile,"r");
//移動到指定位置,開始繼續讀取
raf.seek(lastposition);
//定義集合,用於儲存解析後的日誌
List<LogData> logs = new ArrayList<LogData>();
//迴圈batch次,解析batch條日誌
for(int i=0;i<batch;i++){
/*
* 是否還有日誌可讀
*/
if(!hasLogsByStep(raf)){
break;
}
//讀取使用者名稱
String user = IOUtil.readString(raf,LogData.USER_LENGTH);
//讀取PID
raf.seek(lastposition+LogData.PID_OFFSET);
int pid = IOUtil.readInt(raf);
//讀取type
raf.seek(lastposition+LogData.TYPE_OFFSET);
short type = IOUtil.readShort(raf);
//讀取time
raf.seek(lastposition+LogData.TIME_OFFSET);
int time = IOUtil.readInt(raf);
//讀取host
raf.seek(lastposition+LogData.HOST_OFFSET);
String host = IOUtil.readString(raf, LogData.HOST_LENGTH);
//將RandomAccessFile的遊標位置定位到該條資料的末尾
raf.seek(lastposition+LogData.LOG_LENGTH);
//將lastposition設定為raf的遊標位置,以便下次迴圈使用
lastposition = raf.getFilePointer();
//System.out.println("遊標位置:"+lastposition);
/*
* 將解析出來的資料存入一個LogData物件中,
* 再將該物件存入集合中
*/
LogData log = new LogData(user,pid,type,time,host);
logs.add(log);
}
// System.out.println("解析日誌數:"+logs.size());
// for(LogData log : logs){
// System.out.println(log);
// }
/*
* 將解析後的日誌,寫入log.txt檔案中
*/
IOUtil.saveList(logs, textLogFile);
/*
* 將這次解析後RandomAccessFile的遊標位置記錄,
* 以便於下次解析的時候繼續讀取。
*/
IOUtil.saveLong(lastposition, lastPositionFile);
}catch(Exception e){
}
return false;
}
/**
* 第二大步的:
* 匹配日誌
* 大體步驟:
* 1:讀取log.txt檔案,將第一步解析出的日期讀取出來
* 並轉為若干個LogData物件存入list集合中等待配對
* 2:讀取login.txt檔案,將上次沒有配對成功的登入日誌讀取出來
* 並轉換為若干個LogData物件,也存入List集合中,等待這次配對
* 3:迴圈list,將登入登出日誌分別存入到2個map中,value就是對應的日誌物件,
* key都是【user,pid,ip】這樣格式的字串
* 4:迴圈登出的map,並通過key尋找登入map中的登入日誌,
* 以達到配對的目的,將配對的日誌轉換為一個LogRec物件存入一個list集合中
* 5:將所有配對成功的日誌寫入檔案logrec.txt
* 6:將所有沒配對成功的日誌寫入檔案login.txt
* @return
*/
public boolean matchLogs(){
/*
* 必要的判斷
*/
if(!textLogFile.exists()){
return false;
}
/*
* 當第二步執行完畢後,會生成兩個檔案:logrec.txt, login.txt
* 若第三步在執行時出現錯誤,我們若重新執行第二步,
* 會將上次第二步已經配對的日誌覆蓋,從而導致資料丟失。
* 為此我們要做一個必要的判斷,就是
* logrec.txt檔案若存在,則說明第二步
* 已經完成,但是第三部沒有順利執行。
* 因為第三步執行完畢後,會將該檔案刪除。
* 所以,若存在,則第二步不再執行。
*/
if(logRecFile.exists()){
return true;
}
/*
* 業務邏輯
*/
try{
/*
* 1讀取log.txt檔案,將第一步解析出的日期讀取出來
* 並轉為若干個LogData物件存入list集合中等待配對
*/
List<LogData> list = IOUtil.loadLogData(textLogFile);
/*2讀取login.txt檔案,將上次沒有配對成功的登入日誌讀取出來,
並轉換為若干個LogData物件,也存入List集合中,等待這次配對*/
if(loginFile.exists()){
list.addAll(IOUtil.loadLogData(logRecFile));
}
/*3迴圈list,將登入登出日誌分別存入到2個map中,value就是對應的日誌物件,
key都是【user,pid,ip】這樣格式的字串*/
Map<String,LogData> loginMap = new HashMap<String,LogData>();
Map<String,LogData> logoutMap = new HashMap<String,LogData>();
for(LogData log : list){
if(log.getType()==LogData.TYPE_LOGIN){
putLogToMap(log, loginMap);
}else if(log.getType()==LogData.TYPE_LOGOUT){
putLogToMap(log, logoutMap);
}
}
/*4:迴圈登出的map,並通過key尋找登入map中的登入日誌,
以達到配對的目的,將配對的日誌轉換為一個LogRec物件存入一個list集合中*/
Set<Entry<String,LogData>> set =logoutMap.entrySet();
//用於存放所有配對成功的日誌的集合
List<LogRec> logRecList = new ArrayList<LogRec>();
for(Entry<String,LogData> entry : set){
/*
* 從登出map中,取出key
*/
String key = entry.getKey();
/*
* 根據登出的key,從登入map中
* 以相同的key刪除元素,刪除的
* 就是對應的登入日誌
*/
LogData login = loginMap.remove(key);
if(login!=null){
//匹配後,轉為一個LogRec物件
LogRec logrec = new LogRec(login,entry.getValue());
//將配對日誌存入集合
logRecList.add(logrec);
}
}
//出了for迴圈,相當於配對工作就完畢了
//5:將所有配對成功的日誌寫入檔案logrec.txt
IOUtil.saveList(logRecList, logRecFile);
//6:將所有沒配對成功的日誌寫入檔案login.txt
Collection<LogData> c = loginMap.values();
IOUtil.saveList(new ArrayList<LogData>(c), loginFile);
/*
* 當第二步執行完畢後,
* log.txt檔案就可以刪除了
*/
textLogFile.delete();
return true;
}catch(Exception e){
e.printStackTrace();
/*
* 若第二步出現異常,那麼第二步生成的
* 配對檔案logrec.txt檔案就是無效的。
* 應當刪除,以便於重新執行第二步
*/
if(logRecFile.exists()){
logRecFile.delete();
}
return false;
}
}
/**
* 將給定的日誌存入給定的map中
* @param log
* @param map
*/
private void putLogToMap(LogData log, Map<String,LogData> map){
map.put(log.getUser()+","+log.getPid()+","+log.getHost(), log);
}
/**
* 第三步:
* 將配對的日誌傳送至服務端
* 步驟:
* 1:建立socket用於連線服務端
* 2:通過socket獲取輸出流,並逐步包裝為
* 緩衝字元輸出流,字符集是utf-8
* 3:建立緩衝字元輸入流,用於讀取
* logrec.txt(讀取配對日誌)
* 4:從logrec.txt檔案中讀取每一行日誌資訊
* 併發送至服務端
* 5:通過socket獲取輸入流,並逐步包裝為
* 緩衝字元輸入流,用於讀取服務端的響應
* 6:讀取伺服器的響應,若是ok,則說明
* 服務端成功接收了我們傳送的配對日誌
* 那麼就將logrec.txt檔案刪除。
* 第三步執行完畢。
* 若返回的響應不是ok,則表示傳送沒有
* 成功,那麼該方法返回false,應當
* 重新嘗試執行第三步。
* @return
*/
public boolean sendLogToServer(){
/*
* 必要判斷
*/
if(!logRecFile.exists()){
return false;
}
/*
* 業務邏輯
*/
Socket socket = null;
BufferedReader br = null;
try{
socket = new Socket("localhost",8088);
OutputStream out = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(out,"UTF-8");
PrintWriter pw = new PrintWriter(osw);
//讀取logrec.txt
FileInputStream fis = new FileInputStream(logRecFile);
InputStreamReader isr = new InputStreamReader(fis);
br = new BufferedReader(isr);
String line = null;
/*
* 迴圈從logrec.txt檔案中讀取每一行
* 配對日誌,併發送至服務端
*/
while((line=br.readLine())!=null){
pw.println(line);
}
//最後傳送一個over,表示傳送完畢了
pw.println("over");
pw.flush();
//已經將logrec.txt檔案中的內容傳送了
//傳送完,將讀取檔案的流關掉
br.close();
/*
* 通過socket建立輸入流,用於讀取服務端的響應
*/
InputStream in = socket.getInputStream();
BufferedReader brServer = new BufferedReader(new InputStreamReader(in,"UTF-8"));
//讀取服務端傳送回來的響應
String response = brServer.readLine();
if("OK".equals(response)){
/*
* 服務端正確接收發送的日之後
* 就可以將第二步生成的logrec.txt
* 檔案刪除了。
*/
logRecFile.delete();
return true;
}
return false;
}catch(Exception e){
e.printStackTrace();
return false;
}finally{
//將socket關閉
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
}
}
//讀取檔案的輸入流也可能沒關閉
if(br!=null){
try {
br.close();
} catch (IOException e) {
}
}
}
}
/**
* 客戶端開始工作的方法
*/
public void start(){
/*
* 開始方法中,我們要迴圈以下3個步驟
* 1:從wtmpx檔案中一次解析batch跳日誌
* 2:將解析後的日誌,和上次沒有匹配的日誌一起配成對
* 3:將匹配成對的日誌傳送至服務端
*/
while(true){
//1:從wtmpx檔案中一次解析batch跳日誌
readNextLogs();
//2將解析後的日誌,和上次沒有匹配的日誌一起配成對
matchLogs();
//3
sendLogToServer();
}
}
public static void main(String[] args) {
Client client = new Client();
client.start();
}
}
Server
package com.company;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
/**
* 服務端應用程式
*/
public class Server {
//執行在服務端的socket
private ServerSocket server;
//執行緒池,用於管理客戶端連線的互動執行緒
private ExecutorService threadPool;
//儲存所有客戶端傳送過來的配對日誌的檔案
private File serverLogFile;
//建立一個雙緩衝佇列,用於儲存配對日誌
private BlockingQueue<String> messageQueue;
/**
* 構造方法,用於初始化伺服器
*/
public Server() throws IOException{
try{
/*
* 建立ServerSocket時需要指定伺服器埠
*/
System.out.println("初始化服務端");
server = new ServerSocket(8088);
//初始化執行緒池
threadPool = Executors.newFixedThreadPool(50);
//初始化儲存的日誌
serverLogFile = new File("server-log.txt");
//初始化緩衝佇列
messageQueue = new LinkedBlockingQueue<String>();
System.out.println("伺服器初始化完畢");
}catch(IOException e){
e.printStackTrace();
throw e;
}
}
/**
* 服務端開始工作的方法
*/
public void start(){
try{
/*
* 將寫日誌的執行緒啟動起來
*/
WriteLogThread thread = new WriteLogThread();
thread.start();
/*
* ServerSocket的accept方法
* 用於監聽8088埠,等待客戶端的連線
* 該方法是一個阻塞方法,直到一個
* 客戶端連線,否則該方法一直阻塞。
* 若一個客戶端連線了,會返回該客戶端的
* Socket
*/
while(true){
System.out.println("等待客戶端連線");
Socket socket = server.accept();
/*
* 當一個客戶端連線後,啟動一個執行緒
* ClientHandler,將該客戶端的
* socket傳入,使得該執行緒處理與該
* 客戶端互動。
* 這樣,我們能再次進入迴圈,接收
* 下一個客戶端的連線了。
*/
Runnable handler = new ClientHandler(socket);
//Thread t = new Thread(handler);
//t.start();
/*
* 使用執行緒池分配空閒執行緒來處理
* 當前連線的客戶端
*/
threadPool.execute(handler);
}
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
Server server;
try{
server = new Server();
server.start();
}catch(IOException e){
e.printStackTrace();
System.out.println("伺服器初始化失敗");
}
}
/**
* 服務端中的一個執行緒,用於與某個客戶端互動。
* 使用執行緒的目的是使得服務端可以處理多客戶端了。
*/
class ClientHandler implements Runnable{
//當前執行緒處理的客戶端socket
private Socket socket;
/**
* 根據給定的客戶端的socket,建立
* 執行緒體
* @param socket
*/
public ClientHandler(Socket socket){
this.socket = socket;
}
/**
* 該執行緒會將當前socket中的輸入流獲取
* 用來迴圈讀取客戶端傳送過來的訊息
*/
@Override
public void run() {
/*
* 定義在try語句外的目的是,為了在
* finally中也可以引用到
*/
PrintWriter pw = null;
try{
/*
* 為了讓服務端與客戶端傳送資訊,
* 我們需要通過socket獲取輸出流。
*/
OutputStream out = socket.getOutputStream();
pw = new PrintWriter(
new OutputStreamWriter(out,"UTF-8"), true);
//獲取輸入流
InputStream in = socket.getInputStream();
BufferedReader br = new BufferedReader(
new InputStreamReader(in,"UTF-8"));
String message = null;
/*
* 迴圈讀取客戶端傳送過來的每一組
* 配對日誌
* 讀取到一組,就將該日誌存入
* 訊息佇列,等待被寫入檔案。
*/
while((message=br.readLine())!=null){
/*
* 若讀取到客戶端傳送的內容是over
* 表示客戶端傳送完畢所有的日誌了
* 應當停止再接收客戶端傳送的內容了
*/
if("over".equals(message)){
break;
}
messageQueue.offer(message);
}
/*
* 當退出迴圈,說明所有客戶端傳送的日誌
* 均接收成功,並存入了訊息佇列中。
* 那麼我們回覆客戶端OK
*/
pw.println("OK");
}catch(Exception e){
//在windows中的客戶端,
//報錯通常是因為客戶端斷開了連線
pw.println("ERROR");
}finally{
/*
* 無論是linux使用者還是windows
* 使用者,當與服務端斷開連線後
* 我們都應該在服務端也與客戶端
* 斷開連線
*/
try {
socket.close();
} catch (IOException e) {
}
}
}
}
/**
* 該執行緒在server中僅有一個例項
* 作用是:
* 迴圈從訊息佇列中取出一個配對日誌,
* 並寫入sever-log.txt檔案中
* 當佇列沒有日誌後,就休眠一段時間
* 等待客戶端傳送新的日誌過來
*/
class WriteLogThread extends Thread{
@Override
public void run() {
try{
PrintWriter pw = new PrintWriter(serverLogFile);
while(true){
if(messageQueue.size()>0){
String log = messageQueue.poll();
pw.println(log);
}else{
pw.flush();
Thread.sleep(500);
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
LogData
package com.company.bo;
/**
* LogData的每一個例項用於表示wtmpx檔案中的每一條日誌資訊
*/
public class LogData {
/**
* 日誌wtmpx檔案中的長度
* 每條日誌的長度都是372個位元組
*/
public static final int LOG_LENGTH=372;
/**
* user在單挑日誌中的起始位元組
*/
public static final int USER_OFFSET=0;
/**
* user在日誌中佔用的位元組量
*/
public static final int USER_LENGTH=32;
/**
* pid的起始位置
*/
public static final int PID_OFFSET=68;
/**
* type在日誌中的起始位置
*/
public static final int TYPE_OFFSET=72;
/**
* time在日誌中的起始位置
*/
public static final int TIME_OFFSET=80;
/**
* host在日誌中的起始位置
*/
public static final int HOST_OFFSET=114;
/**
* host在日誌中的長度
*/
public static final int HOST_LENGTH=258;
/**
* 日誌型別:登入為7
*/
public static final short TYPE_LOGIN=7;
/**
* 日誌型別:登出為8
*/
public static final short TYPE_LOGOUT=8;
//登入使用者名稱
private String user;
//程序id
private int pid;
//日誌型別(登入/登出)
private short type;
//生成日誌的時間(登入登出的時間),以秒為單位
private int time;
//登入使用者的ip地址
private String host;
public LogData(){}
public LogData(String user, int pid, short type, int time, String host) {
super();
this.user = user;
this.pid = pid;
this.type = type;
this.time = time;
this.host = host;
}
/**
* 給定一個字串
* (格式應該是當前類toString方法生成)
* 將該字串轉換為一個LogData物件
*/
public LogData(String line){
//1:按照“,”拆分字串
String[] array = line.split(",");
//2:將陣列中的每一項設定到屬性上即可
this.user = array[0];
this.pid = Integer.parseInt(array[1]);
this.type = Short.parseShort(array[2]);
this.time = Integer.parseInt(array[3]);
this.host = array[4];
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public int getPid() {
return pid;
}
public void setPid(int pid) {
this.pid = pid;
}
public short getType() {
return type;
}
public void setType(short type) {
this.type = type;
}
public int getTime() {
return time;
}
public void setTime(int time) {
this.time = time;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
@Override
public String toString() {
return user + "," + pid + "," + type + "," + time + "," + host;
}
}
LogRec
package com.company.bo;
/**
* 該類用於描述一組匹配成對的日誌
*/
public class LogRec {
private LogData login;
private LogData logout;
public LogRec(LogData login, LogData logout) {
super();
this.login = login;
this.logout = logout;
}
public LogData getLogin() {
return login;
}
public void setLogin(LogData login) {
this.login = login;
}
public LogData getLogout() {
return logout;
}
public void setLogout(LogData logout) {
this.logout = logout;
}
/**
* toString()
* 格式:
* login.toString()|logout.toString()
*/
@Override
public String toString() {
return login + "|" +logout.toString();
}
}
IOUtil
package com.company.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;
import com.company.bo.LogData;
/**
* 該類是一個工具類,負責讀寫資料,
* 把讀寫邏輯單獨定義在該類的目的是為了重用這些邏輯。
*/
public class IOUtil {
/**
* 從給定的檔案中讀取第一行字串,
* 並將其轉為一個long值返回
*/
public static long readLong(File file){
BufferedReader br = null;
try{
FileInputStream fis = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(fis);
br = new BufferedReader(isr);
String line = br.readLine();
long l = Long.parseLong(line);
return l;
}catch(Exception e){
e.printStackTrace();
throw new RuntimeException(e);
}finally{
try {
if(br != null){
br.close();
}
} catch (IOException e) {
}
}
}
/**
* 從給定的RandomAccessFile的當前位置處
* 連續讀取len個位元組,並轉為字串
*/
public static String readString(RandomAccessFile raf, int len) throws IOException{
byte[] buf = new byte[LogData.USER_LENGTH];
raf.read(buf);
String str = new String(buf,"ISO8859-1");
return str.trim();
}
/**
* 從給定的RandomAccessFile當前位置處,
* 讀取一個int值並返回
*/
public static int readInt(RandomAccessFile raf) throws IOException{
return raf.readInt();
}
/**
* 從給定的RandomAccessFile當前位置處,
* 讀取一個short值並返回
*/
public static short readShort(RandomAccessFile raf) throws IOException{
return raf.readShort();
}
/**
* 將給定的集合中的每個元素的toString方法返回的字串
* 作為一行內容寫入給定的檔案中
*/
public static void saveList(List list,File file) throws IOException{
PrintWriter pw = null;
try {
pw = new PrintWriter(file);
for(Object o : list){
pw.println(o);
}
}finally{//異常丟擲,故不catch,但流要關閉
if(pw != null){
pw.close();
}
}
}
/**
* 將給定的long值作為一行字串寫入給定的檔案中
*/
public static void saveLong(long l,File file) throws IOException{
PrintWriter pw =null;
try{
pw = new PrintWriter(file);
pw.println(l);
}finally{//異常丟擲,故不catch,但流要關閉
if(pw!=null){
pw.close();
}
}
}
/**
* 從指定的檔案中按行讀取每一條日誌,並
* 轉換為一個LogData物件,最終將所有日誌
* 物件存入一個List集合中並返回
* @param file
* @return
*/
public static List<LogData> loadLogData(File file) throws IOException{
BufferedReader br = null;
try{
FileInputStream fis = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(fis);
br = new BufferedReader(isr);
List<LogData> list = new ArrayList<LogData>();
String line = null;
while((line=br.readLine()) != null){
/*
* 解析過程應當交給LogData
* 原因在於該字串的格式是由LogData自身的toString決定的
* 所以解析自然也應該交給它
*/
LogData log = new LogData(line);
list.add(log);
}
return list;
}finally{
if(br != null){
br.close();
}
}
}
}
相關推薦
挖掘機(DMS)(伺服器與客戶端讀寫檔案,收發資料)
Client package com.company; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IO
C#.網路程式設計 Socket基礎(四) WPF系統Socket TCP協議 伺服器與客戶端 不同型別檔案傳輸,同時解決UI執行緒與工作執行緒的卡頓問題
一、簡介 雖然,本文的前面幾篇文章在WinForm中實現了Socket TCP協議 伺服器與客戶端 不同型別檔案傳輸,詳情見 但是,卻沒有在WPF中實現 Socket TCP協議 伺服器與客戶端 不同型別檔案傳輸。因此,本文將描述如何在WPF中實現該功能。
Linux下簡單的網路程式設計筆記(模擬簡單的伺服器與客戶端的通訊 1-伺服器端)
一.伺服器端 (一).建立連線的條件:伺服器必須處於監聽狀態,由客戶端發起連線請求 bind之前可新增以下程式碼解決關閉伺服器後端口仍被佔用的問題 // 設定套接字選項避免地址使用錯誤 int on=1; if((setsoc
linux c伺服器與客戶端之間的檔案傳輸
最近做了一下linux C網路方面的專案,簡單的寫了一下伺服器於客戶端之間上傳,下載檔案,利用併發伺服器,可以實現多個客戶端同時上傳,下載。 寫的不好,還請大神多多指教!多的不說,一切都在程式碼中,部分程式碼如下所示: /*server.c */ 伺服器端 void *re
C#Socket通訊基礎(非同步Socket通訊TCP)伺服器與客戶端
一、效果圖 二、伺服器端程式碼(原始碼下載地址:https://download.csdn.net/download/xiaochenxihua/10748789) using System; using System.Collections.Generic; using System
【隨堂筆記】unity中socket的用法(二、伺服器與客戶端之間簡單的資料傳遞)
主要實現伺服器與客戶端之間簡單的資料傳輸(單次) 伺服器程式碼 using System; using System.Net; using System.Net.Sockets; namespace SeverSocket { class Program {
【隨堂筆記】unity開發中Socket的用法(一,實現伺服器與客戶端簡單的連結)
實現了簡單的連結,也增加了客戶端沒有連結到伺服器的自動重連 伺服器程式碼 using System; using System.Net; using System.Net.Sockets; namespace SeverSocket { class Program
【開發筆記】Unity聯網鬥地主的實現(一,伺服器與客戶端的資料傳遞流程)
話不多說,先上我李老師的思維導圖 大致構思了一個框架 1.首先要定義一下伺服器與客戶端的傳輸協議,必須保持一致 2.定義服務於客戶端傳輸的訊息型別,如(申請加入,同意加入,出牌,之類的) 3.定義一下牌的型別,出的牌的型別,在客戶端判斷是否可以出牌,牌型傳給伺服器,伺服器在完成三個玩家的出
python 實戰之模仿開發QQ聊天軟體(三)TCP/IP伺服器與客戶端建設
無論是p2p還是c/s還是b/s,只要用到通訊,必然是要用到今天寫的這個。 TCP/IP是網路軟體最核心的部分,缺少這個你只能當做單機遊戲玩。 TCP/IP,只需要搞清楚udp和tcp這兩個就可以了。 兩者的區別在於 udp每次傳送資訊都需要傳送ip和埠號,可以比
C#.網路程式設計 Socket基礎(一)Socket TCP協議 實現端到端(伺服器與客戶端)簡單字串通訊
簡介: 本章節主要討論了Socket的入門知識,還未針對Socket的難點問題(比如TCP的無訊息邊界問題)展開討論,往後在其他章節中進行研究。 注意點: 伺服器(比如臺式電腦)的IP為1.1.1.2,那麼客戶端(其他裝置,比如手機,Ipad)連線的一定是
C#.網路程式設計 Socket基礎(三) 基於WinForm系統Socket TCP協議 實現端到端(伺服器與客戶端).txt.word.png等不同型別檔案傳輸
一、簡介: 前面的兩篇介紹了字串傳輸、圖片傳輸: 其實,本文針對Socket基礎(二)進一步完成,以便可以進行多種檔案傳輸。 二、基於不同的流(檔案流、記憶體流、網路等)讀寫。 1、圖片傳輸 方法一:(在客戶端用檔案流傳送(即將圖片寫到檔案流去,以便傳送),
zabbix伺服器與客戶端(Linux+Windows)的搭建
zabbix監控搭建 一、搭建LNMP環境(MySQL) 建立資料庫以及授權Qy123123. mysql> create database zabbix character set utf8; mysql> grant all on zabbix.* to [email p
Java實現簡單的Socket伺服器與客戶端字串通訊(適合初學者閱讀)
近段時間,頻繁看到很多學生做畢業設計用到了Socket通訊技術,問題非常多,特寫一個小例子,希望對馬上畢業的同學有所幫助。如果希望學習的更加深入,需要掌握的知識有:面向物件、多執行緒、Socket通訊、IO流、異常處理 伺服器端程式碼: import java
Qt實現伺服器與客戶端傳輸文字和圖片(Qt②)
初學者記錄學習內容,如有錯誤請各位前輩指點。 此次工程完成過程借鑑了下面得兩個帖子,附上鍊接,並致以感謝: qt 寫的tcp客戶端程式實現簡單的連線接受和傳送訊息 qt寫的一個簡單的tcp伺服器程式,可以接受訊息傳送資料 好了閒話少說進入正題。 瞭解C
socket程式設計(一),實現伺服器與客戶端簡單通訊
本節主講客戶端向服務傳送資訊,伺服器轉發給客戶端,當然也可以稍微改一下程式碼可以實現互傳訊息,不再贅述。 難點在於伺服器端的程式碼思路: (1)主程式Socket socket=server.acc
C# Socket簡單例子(伺服器與客戶端通訊)
這個例子只是簡單實現瞭如何使用 Socket 類實現面向連線的通訊。注意:此例子的目的只是為了說明用套接字寫程式的大概思路,而不是實際專案中的使用程式。在這個例子中,實際上還有很多問題沒有解決,如訊息邊界問題、埠號是否被佔用、訊息命令的解析問題等。。下面是兩個程式的程式碼,(
Redis原始碼剖析(一)伺服器與客戶端互動流程
Redis中的C/S模型 Redis底層還是基於網路請求的,對於單機資料庫而言,網路請求僅僅是在一臺機器上互動,即伺服器客戶端都在一臺計算機上 當在終端輸入redis-serve時,便啟動了一個Redis伺服器,隨後開始初始化內部資料,對於Redis而言包括
一個基於TCP/IP的伺服器與客戶端通訊的小專案(超詳細版)
1.目的:實現客戶端向伺服器傳送資料 原理: 2.建立兩個控制檯應用,一個為伺服器,用於接收資料。一個為客戶端,用於傳送資料。 關鍵類與對應方法: 1)類IPEndPoint: 1.是抽象類EndPoint的實現類 2.So
ROS學習筆記18 (編寫簡單的伺服器和客戶端 (C++))
1 編寫Service節點 這裡,我們將建立一個簡單的service節點("add_two_ints_server"),該節點將接收到兩個整型數字,並返回它們的和。 進入先前你在catkin workspace教程中所建立的beginner_tutorials包所在的目錄
ROS學習筆記19 (編寫簡單的伺服器和客戶端 (Python))
1 編寫服務端節點 我們會建立服務端節點 ("add_two_ints_server") ,節點接收兩個整型數字,並返回和 進入beginner_tutorials包 $ roscd beginner_tutorials 確保你確保已經在之前建立好AddTwoInts