Java第十七课_IO流和线程

发布时间 2023-12-26 09:20:44作者: 张心野

1.IO流

  • 序列化

    public class Practice01 {
    
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            // 一个数据            用变量
            // 多个同类型数据      用数组
            // 多个不类型数据      用对象
            // 多个对象           用对象数组 / 集合
    
            // 序列化 :
            writeObjectToFile(new User("lisi", 20, 0), "user.txt");
            User user = readObjectFromFile(User.class, "user.txt");
            System.out.println(user);
        }
    
        public static <T> T readObjectFromFile(Class<T> clazz,String fileName) throws IOException, ClassNotFoundException {
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(fileName));
            T t = (T) objectInputStream.readObject();
            objectInputStream.close();
            return t;
        }
    
        public static <T> void writeObjectToFile(T t, String fileName) throws IOException {
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(fileName));
            objectOutputStream.writeObject(t);
            objectOutputStream.close();
        }
    }
    
    public class User implements Serializable{
    
        //IO流项目中, 类都要实现Serializable(包括类中类等), 并声明一个固定的serialVersionUID.
        //      每次运行时随机分配UID的话, 可能会导致过程中类文件变动后, 找不到序列号错误
        private static final long serialVersionUID = 1024L;
    
        private String name;
        private int age;
        private double height;
        private Date birthday;
        private Fimaly fimaly = new Fimaly();
    
        public User() {
        }
    
        public User(String name, int age, double height) {
            this.name = name;
            this.age = age;
            this.height = height;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", height=" + height +
                    ", birthday=" + birthday +
                    ", fimaly=" + fimaly +
                    '}';
        }
    }
    
    public class Fimaly implements Serializable {
    
        private static final long serialVersionUID = 125L;
    }
    
  • 字符流

        public static void main(String[] args) throws IOException {
            // 字符流 每次读写一个字符,只能操作文本文件
    		// 字符流只可以用于字符, 读写其他资源时因为格式不同, 会乱码
            
            // Writer : 可以直接写入字符
            //      OutputStreamWriter 是字符流通向字节流的桥梁
            Writer writer = new OutputStreamWriter(new FileOutputStream("a.txt"));
            writer.write('话');
            writer.write('A');
            writer.write('B');
            writer.write('C');
            char[] chars = "华夏ABC".toCharArray();
            writer.write(chars);
            writer.write(chars, 0, 4);
            writer.close();
            System.out.println("-------------------------------");
    
            // Reader : 读出时不管字符几个字节, 会一个字符一个字符读出.
            //  InputStreamReader 是字节流通向字符流的桥梁
            Reader reader = new InputStreamReader(new FileInputStream("a.txt"));
    
            int read = reader.read();// 输出值为int, 只能看到字符的int值
            System.out.println("read = " + read);
            System.out.println((int) '话');
            read = reader.read();
            System.out.println("read = " + read);
    
            char[] chars1 = new char[6];// 常规用法是利用字符数组
            int len = reader.read(chars1);
            System.out.println("len = " + len);
            System.out.println("Arrays.toString(chars1) = " + Arrays.toString(chars1));
            len = reader.read(chars1);
            System.out.println("len = " + len);
            System.out.println("Arrays.toString(chars1) = " + Arrays.toString(chars1));// 只剩四个字符, 只覆盖前四个成员
            len = reader.read(chars1);
            System.out.println("len = " + len);
            System.out.println("Arrays.toString(chars1) = " + Arrays.toString(chars1));// 无剩余字符, 返回-1, 不会覆盖
            reader.close();
        }
    
  • 字符集

        public static void main(String[] args) throws IOException {
            // 字符IO流可以设定文件中字符的格式. 但是如果设定了和字符不同的字符集, 就会出现乱码
            InputStreamReader inputStreamReader =
                    new InputStreamReader(new FileInputStream("a.txt"), "GBK");
    
            // Writer默认覆盖之前的内容, 如果想追加, 需要将参数设为true
            OutputStreamWriter outputStreamWriter =
                    new OutputStreamWriter(new FileOutputStream("a.txt", true), StandardCharsets.UTF_8);
    
            int len ;
            char[] chars = new char[1024];
            while ((len = inputStreamReader.read(chars)) != -1) {
                outputStreamWriter.write(chars, 0, len);
            }
            outputStreamWriter.close();
            inputStreamReader.close();
        }
    
  • 便捷流

        public static void main(String[] args) throws IOException {
            // 便捷流 : 不再需要new FileIO的桥梁, 可以直接给文件名(类内部自己有new FileIO)
            // FileReader
            // FileWriter
            FileReader fileReader = new FileReader("a.txt");
            FileWriter fileWriter = new FileWriter("b.txt");
    
            int len;
            char[] chars = new char[1024];
    
            while ((len = fileReader.read(chars)) != -1) {
                fileWriter.write(chars, 0, len);
            }
            fileWriter.close();
            fileReader.close();
        }
    
  • 字符缓冲流

        public static void main(String[] args)throws IOException {
            // 字符缓冲流
            // BufferedReader
            // BufferedWriter
            BufferedReader bufferedReader = new BufferedReader(new FileReader("b.txt"));
            BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("a.txt"));
    
            String info = bufferedReader.readLine();
            while (info != null) {
                bufferedWriter.write(info);
                bufferedWriter.newLine();
                bufferedWriter.flush();
                info = bufferedReader.readLine();
            }
    
            bufferedWriter.close();
            bufferedReader.close();
        }
    
  • 便捷输出流

        public static void main(String[] args) throws FileNotFoundException {
            // 便捷输出流 :
            // PrintStream
            PrintStream printStream = new PrintStream(new FileOutputStream("e.txt", true));
    
            // 从键盘接收数据写入文件
            System.out.println("请输入数据(输入exit退出)");
            Scanner scanner = new Scanner(System.in);
    
            while (true) {
                String info = scanner.next();
                if ("exit".equals(info)) {
                    break;
                }
                printStream.println(info);
                printStream.flush();
            }
            printStream.close();
    
            System.out.println("---------------------");
            // PrintWriter
            PrintWriter pw = new PrintWriter(new FileOutputStream("exception.txt"), true);
    
            try {
                System.out.println(10/0);
            } catch (Exception e) {
                e.printStackTrace(pw);
            }
        }
    
  • IO流阻塞

        public static void main(String[] args) throws IOException {
            // IO流阻塞 : 让IO流, 在其他任务(如System.in, 等用户先输入数据)完成后再IO
            System.out.println("请输入");
            InputStream inputStream = System.in;
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            String line = bufferedReader.readLine();
            System.out.println("line = " + line);
    
            int num = 0;
            try {
                num = Integer.parseInt(line);
            } catch (NumberFormatException e) {
                throw new InputMismatchException(e.getMessage() + " 不是数字! ");
            }
            System.out.println("num = " + num);
            bufferedReader.close();
            inputStream.close();
        }
    

2.线程

  • 线程01

        public static void main(String[] args) {
            // 程序/软件 : 静态的,不会自己运行的,是一堆指令,存在于硬盘上的.
            // 进程 : 程序的一次运行 , 也就是运行中的程序
            // 线程 : 进程执行过程中的分支 , 主进程也称为 主线程
    
            // Thread 线程类. 三种方式:
            //      1.类继承Thread, 并重写run函数(在run中定义任务)
            MyThread01 myThread01 = new MyThread01();
            myThread01.start();// 启动线程
    
    
            //      2(常用).类实现Runnable接口,  并重写run函数(在run中定义任务)
            MyThread02 myThread02 = new MyThread02();
            Thread thread = new Thread(myThread02);
            thread.start();
    
            for (int i = 0; i < 10; i++) {
                System.out.println("main : i = " + i);
            }
    
            // 每个线程都有自己默认的名字 :  Thread-0   -1 -2 ... 主线程是main
            //      可以在各个线程里调用Thread.currentThread()的功能
            for (int i = 100; i < 110; i++) {
                System.out.println(Thread.currentThread().getName() + "  ~~~~~~~~~  i = " + i);
            }
        }
    
    public class MyThread01 extends Thread{
    
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println("MyThread01 : i = " + i);
            }
        }
    }
    
    public class MyThread02 implements Runnable{
    
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println("MyThread02 : i = " + i);
            }
        }
    }
    
  • 线程02

        public static void main(String[] args) throws InterruptedException {
            // 线程应该用继承还是实现?
            // 1.类与类之间单继承,类与接口之间多实现
            // 2.继承不会共享数据 , 实现可以共享数据
    
            class MyThreadA extends Thread{
                int count = 8;
                @Override
                public void run() {
                    while (count > 0) {
                        System.out.println(Thread.currentThread().getName() + " :: " + count--);
                    }
                }
            }
            MyThreadA myThreadA1 = new MyThreadA();
            MyThreadA myThreadA2 = new MyThreadA();
            // 同一个线程只能启动一次 , 否则 会有 IllegalThreadStateException
            // 开两个线程就要创建两个对象, 各自start
            myThreadA1.start();
            myThreadA2.start();
    
            MyThreadB myThreadB = new MyThreadB();// 实现可以共享数据
            Thread thread1 = new Thread(myThreadB);
            Thread thread2 = new Thread(myThreadB);
            thread1.start();
            thread2.start();
        }
    
        static class MyThreadB implements Runnable{
            int count = 8;
            @Override
            public void run() {
                while (count > 0) {
                    System.out.println(Thread.currentThread().getName() + " :: " + count--);
                }
            }
        }
    
  • 线程优先级

        public static void main(String[] args) {
            // 线程优先级 : 1~10 , 默认为 5
    		// 开发中一般没用, 不会体现.(可能是因为资源充足, 等资源急缺时, 才会体现优先级)
            
            class MyThread implements Runnable{
                @Override
                public void run() {
                    for (int i = 0; i < 20; i++) {
                        System.out.println(Thread.currentThread().getName() + " :: " + Thread.currentThread().getPriority());
                    }
                }
            }
    
            Thread thread1 = new Thread(new MyThread());
            Thread thread2 = new Thread(new MyThread());
            thread1.setName("郭靖");
            thread2.setName("黄蓉^_^");
    
            thread1.setPriority(Thread.MIN_PRIORITY);
            thread2.setPriority(Thread.MAX_PRIORITY);
    
            thread1.start();// 没有体现.
            thread2.start();
        }
    
  • 守护线程

        public static void main(String[] args) {
            // 守护线程 : 当所有的用户线程结束时 , 守护线程随之结束
            // 一般线程都默认为用户线程(包括主函数)
    
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        System.out.println("run forever ......");
                    }
                }
            });
            // 设为守护线程
            thread.setDaemon(true);
            thread.start();
    
            for (int i = 0; i < 20; i++) {
                System.out.println(Thread.currentThread().getName() + "  ::  " + i);
                System.out.println("thread.isDaemon() = " + thread.isDaemon());
                System.out.println("Thread.currentThread().isDaemon() = " + Thread.currentThread().isDaemon());
            }// 主函数结束后守护线程还要跑一会再结束
        }
    
  • 正确的停止线程的方式

        public static void main(String[] args) {
            // 正确的停止线程的方式 :
            class MyThread implements Runnable{
                private boolean flag = true;
    
                @Override
                public void run() {
                    while (flag) {
                        System.out.println("run forever..... ");
                    }
                }
    
                public boolean isFlag() {
                    return flag;
                }
    
                public void setFlag(boolean flag) {
                    this.flag = flag;
                }
            }
            MyThread myThread = new MyThread();
            new Thread(myThread).start();
    
            for (int i = 0; i < 20; i++) {
                if (i == 10) {
                    myThread.setFlag(false);
                    System.out.println("杀死了线程..........");
                }
                System.out.println(Thread.currentThread().getName() + " :: " + i);
            }
        }