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


















  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值