1. 程式人生 > >挖掘機(DMS)(伺服器與客戶端讀寫檔案,收發資料)

挖掘機(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