package org.ddl.chat; import java.io.*; import java.util.ResourceBundle; import java.util.Scanner; /** * 这是一个读取聊天记录的线程类 */ public class MyRunner implements Runnable { //经常变动 或 重复使用的数据,我们将其声明为类变量 private boolean isUpdate; //文件更新标识 private long lastTime = 0;//文件更新时间 private String fileName = "D:/chat.log"; //默认文件名,也可通过配置文件去改变 private File chatFile; //聊天文件 private InputStreamReader read; private BufferedReader bufferedReader; private String currentName;//当前用户 //实例创建时的的构造函数, 创建该实例时,将当前的用户名传入 public MyRunner(String name) { this.currentName = name;//设置当前用户 try { //设置当前类的 聊天文件,及读取文件的read.?为什么要在构造函数去声明这些东西,而不是在使用时? ResourceBundle bundle = ResourceBundle.getBundle("pro"); fileName = bundle.containsKey("CHAT_FILE") ? bundle.getString("CHAT_FILE") : fileName; chatFile = new File(fileName); if (!chatFile.exists()) { chatFile.createNewFile(); } read = new InputStreamReader( new FileInputStream(chatFile), "GBK");//考虑到编码格式 bufferedReader = new BufferedReader(read); } catch (Exception e) { System.out.println(e.getMessage()); } } //这里的调用是 创建一个线程 start后,线程会在后台去执行run方法,而不是主线程中?什么是主线程,在main的执行过程都叫主线程。。 @Override public void run() { try { while (true) { //循环检测 if (isChange()) { //调用函数,文件是否有更新 readFile(); //有更新就去读文件 } Thread.sleep(1000);//检测一次休息0.1秒 } } catch (Exception e) { System.out.println(e.getMessage()); } } //读取文件 public void readFile() { try { String lineTxt = null; while ((lineTxt = bufferedReader.readLine()) != null) { if (!lineTxt.startsWith(this.currentName)) { System.out.println(lineTxt); } } } catch (Exception e) { System.out.println("读取文件内容出错"); e.printStackTrace(); } } //判断文件有没有更新的方法 public boolean isChange() { long lastTime = chatFile.lastModified(); //局部变量,与对象全局变量一样时,注意是如何使用 isUpdate = this.lastTime != lastTime; this.lastTime = lastTime; return isUpdate; } //快速测试类main public static void main(String[] avgr){ Scanner scanner = new Scanner(System.in); System.out.println("Pls input english name:"); String name = scanner.next() + ":"; //进来系统后,要求输入用户名 //new Thread()是java 创建线程的 语法,需要传入,一个你自己实现的的Thread MyRunner runner=new MyRunner(name); //将自己定义的线程实现类创建 Thread thread=new Thread(runner); //将扔进java的线程 thread.start(); //启动线程 // (new Thread(new MyRunner(name))).start(); //上面的三个步骤一行来写,通常在你知道这个对象只会声明这一次时,才敢这么写!!!(啥叫只声明一次?) 比如,我们的线程,启起来了,就不用动了!(也就是常说的,这个对象创建后,后面不需要引用他,就没有必要去声明一个变量) //下面是针消息发送时,写文件!(整个的过程是 用户写消息到文件,同时,用户通过线程去监听有没有新消息,有的话就把新的消息打印出来). File file = new File("d:/chat.log"); FileWriter fw; PrintWriter printStream; try { while (true) { fw = new FileWriter(file, true); printStream = new PrintWriter(fw); printStream.println(name + scanner.next()); printStream.close(); Thread.sleep(500); } } catch (Exception e) { System.out.println(e.getMessage()); } } }