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


















發佈了0 篇原創文章 · 獲贊 7 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章