zoukankan      html  css  js  c++  java
  • 自学Java基础知识第十七天

    day17

    1. 字符流

    1.1 字节流读取中文文本乱码问题

    问题 : 使用字节输入流读取带有中文文本文件, 一边读取文件, 一边查看文件内容, 导致了按照字节进行读取, 有可能将中文拆分开, 将拆分的不完成的字节转换成字符, 于是发生数据读取出来乱码问题

    解决 : 当读取带有中文文本时, 不要使用字节流, 使用字符流进行操作即可

    代码

    package com.ujiuye.io;

    import java.io.FileInputStream;

    import java.io.IOException;

    public class Demo01_字节流读取中文文本乱码 {

    public static void main(String[] args) throws IOException{

             FileInputStream fis = new FileInputStream("中文.txt");

             byte[] b = new byte[2];

             int len;

             while((len = fis.read(b)) != -1) {

              System.out.print(new String(b,0,len));

             }

             fis.close();

    }

    }

    读取结果:  ?? 就是出现了乱码

     

    源文件内容:

     

    1.2 字符流读取文件原理

       所有文件都是由字节组成, 字符流也是从文件中读取出字节数据, 字符流先从文件中读取出一个字节, 验证这个字节结果是否为一个正数, 证明读到了一个符号, 一个字母,一个数字, 那么直接参考编码表将字节转换成字符数据获取到;

       平台默认的编码表GBK, 中文占有2个字节, 中文第一个字节为负数, 如果从文件中读取到第一个字节为负数, 证明读取到中文, 动态向下读取出一个字节, 将两个字节的结果转换成整数, 参考编码表转换成一个字符

    1.3 字符输入流

    1. Reader : 字符输入流的抽象父类, 来自于java.io, 抽象类不能实例化对象, 需要子类, FileReader
    1. FileReader 构造方法:

       FileReader(String path) : path所表示的文件路径分装在字符输入流中, 以后输入流重文件中读取出字符数据

    FileReader(File path) : path所表示的文件路径分装在字符输入流中, 以后输入流重文件中读取出字符数据

    1. 读取文件方法:

    1) read() : 表示每次从文件中读取出一个字符, 返回值类型int, 如果返回-1,证明文件读取完毕

    2) read(char[] ch) : 表示每次最多从文件中读取出ch.length个字符, 将读取到的字符结果放置到参数数组ch, 返回值类型int, 表示每次读取到的字符个数, 如果返回-1, 证明文件读取完毕

    3) close() : 关闭资源

    代码

    package com.ujiuye.io;

    import java.io.FileReader;

    import java.io.IOException;

    public class Demo02_字符流读取中文文本 {

    public static void main(String[] args) throws IOException{

            // 1. 创建出字符输入流, 绑定一个数据源

    FileReader fr = new FileReader("中文.txt");

    // 2. 使用单个字符读取文件

    // len表示每次读取到的字符对应的整数结果

    /*int len;

    while((len = fr.read()) != -1) {

    System.out.print((char)len);

    }*/

    // len表示每次读取到的字符个数

    int len;

    char[] ch = new char[2];

    while((len = fr.read(ch)) != -1) {

    System.out.print(new String(ch,0,len));

    }

    // 3. 关闭资源

    fr.close();

    }

    }

    1.4 字符输出流

    1. Writer : 是字符输出流抽象父类, 来自于java.io, 抽象类不能实例化对象, 需要一个子类FileWriter
    1. FileWriter构造方法:

       FileWriter(String path) : path所表示的文件路径封装在字符输出流中, 以后输出流向文件中写入字符数据

    FileWriter(File path) : path所表示的文件路径封装在字符输出流中, 以后输出流向文件中写入字符数据

    1. 向文件中写入字符方法:

      

      

    代码

    package com.ujiuye.io;

    import java.io.FileWriter;

    import java.io.IOException;

    public class Demo03_字符流向文件中写入数据 {

    public static void main(String[] args) throws IOException{

           // 1. 创建出一个字符输出流, 绑定一个数据目的

    FileWriter fw = new FileWriter("字符流.txt");

    // 2. 写入单个字符

    fw.write('a');

    // 写入字符数组

    char[] ch = {'A','1','?',''};

    fw.write(ch);

    // 写入字符数组的一部分

    fw.write(ch, 1, 2);

    // 写入字符串

    String s = "今天星期二";

    fw.write(s);

    // 写入字符串的一部分

    fw.write(s, 0, 1);

    fw.close();

    }

    }

    1.5 flushclose方法

    FileWriter 类型, 底层带有默认的数组缓冲, 使用数组的方式写入文件, 如此提高文件读写效能, 如果向文件中写入内容时, 没有刷新数据,也没有关闭资源, 数据都存储在底层数组缓冲区中, 没有同步到文件中, 因此文件中有可能缺失数据

    1. flush() : 表示刷新, IO流资源存在于底层缓冲区中的数据, 同步到文件中, 流资源刷新之后, 还能继续使用
    2. close() : 表示关闭资源, 在关闭资源之前, 先调用flush功能, 将底层缓冲区中的数据, 同步到文件中, 然后在关闭资源, 关闭流资源之后, 流不能在继续使用

    代码

    package com.ujiuye.io;

    import java.io.FileWriter;

    import java.io.IOException;

    public class Demo03_字符流向文件中写入数据 {

    public static void main(String[] args) throws IOException{

           // 1. 创建出一个字符输出流, 绑定一个数据目的

    FileWriter fw = new FileWriter("字符流.txt");

    //aA1?1?今天星期二今

    // 2. 写入单个字符

    fw.write('a');

    // 写入字符数组

    char[] ch = {'A','1','?',''};

    fw.write(ch);

    // 写入字符数组的一部分

    fw.write(ch, 1, 2);

    fw.flush();

    // 写入字符串

    String s = "今天星期二";

    fw.write(s);

    // 写入字符串的一部分

    fw.write(s, 0, 1);

    fw.close();

    }

    }

    1.6 字符流复制

    1. 字符流可以复制纯文本文件(纯文本文件表示可以使用txt记事本打开文件, 打开后可以读懂),但是不建议使用, 效率低

       

    1. 字符流不能复制非纯文本文件, 例如 : 图片,视频...一律不能复制

       

     

    1. 字节流和字符流使用:

       a : 如果做文件的复制, 建议字节流完成复制

       b : 如果有带有中文文件, 边读边看, 防止中文乱码问题出现, 使用字符流进行文件内容的读取

    复制文本文件代码

    package com.ujiuye.io;

    import java.io.FileReader;

    import java.io.FileWriter;

    import java.io.IOException;

    public class Demo04_字符流可以复制文本 {

    public static void main(String[] args) throws IOException{

             FileReader fis = new FileReader("字符流.txt");

             FileWriter fw = new FileWriter("字符流copy.txt");

             

             int len;

             while((len = fis.read()) != -1) {

              fw.write(len);

             }

             

             fw.close();

             fis.close();

    }

    }

    复制非纯文本文件代码

    package com.ujiuye.io;

    import java.io.FileReader;

    import java.io.FileWriter;

    import java.io.IOException;

    public class Demo05_字符流不能复制非纯文本 {

    public static void main(String[] args) throws IOException{

    FileReader fis = new FileReader("D:\0810Java系统班\day16\图解\IO流向.png");

            FileWriter fw = new FileWriter("D:\IO流向.png");

            

            int len;

            while((len = fis.read()) != -1) {

             fw.write(len);

            }       

            fw.close();

            fis.close();

    }

    }

    1.7 字符高效缓冲流

    1. BufferedReader : Reader一个子类, 表示高效字符输入流, 包装类, 将一个普通字符输入流包装成一个高效字符输入流

      BufferedReader(Reader in)

      a : 高效原理, 当创建出一个BufferedReader 字符输入流时, 类型底层会默认创建出一个大小为8192的字符数组, 每次通过read方法读取内存时, 最多读取出8192个字符, 将读取到字符放置到底层数组缓冲区中, 以后读取从数组中读取内容, 减少与磁盘文件交互次数,从而提高读写性能. 一直到文件读取完毕为止

    1. BufferedWriter : Writer一个子类, 表示高效字符输出流, 保证类, 将一个普通字符输出流包装成一个高效字符输出流

      BufferedWriter(Writer in)

       b :高效原理, 当创建出一个BufferedWriter字符输出流时, 类型底层默认创建出一个大小为8192的字符数组, 向文件中写入字符内容, 先写入到底层数组缓冲中, 当将8192写满,或者通过flush以及close方法, 可以将缓冲区中的数据同步到文件中, 减少与磁盘文件交互次数,从而提高读写效能

    代码

    package com.ujiuye.io;

    import java.io.BufferedReader;

    import java.io.BufferedWriter;

    import java.io.FileReader;

    import java.io.FileWriter;

    import java.io.IOException;

    public class Demo06_字符高效缓冲流 {

    public static void main(String[] args) throws IOException{

            // 1. 定义出高效缓冲流

    BufferedReader br = new BufferedReader(

    new FileReader("Info.txt"));

    BufferedWriter bw = new  BufferedWriter(

    new FileWriter("InfoCopy.txt"));

    // 2. 边读边写

    // len表示每次读取到的字符转换成整数结果

    int len;

    while((len = br.read()) != -1) {

    bw.write(len);

    }

    bw.close();

    br.close();

    }

    }

    1.8 字符高效缓冲流特有方法

    1. BufferedReader: 有特有方法

       readLine() :  每次可以从文件中读取出一行数据, 读取出数据返回值类型String, 当读取到null, 证明文件读取完毕

    1. BufferedWriter: 有特有功能

       newLine() : 表示向文件中写入一次回车换行

    代码

    package com.ujiuye.io;

    import java.io.BufferedReader;

    import java.io.BufferedWriter;

    import java.io.FileReader;

    import java.io.FileWriter;

    import java.io.IOException;

    import java.util.Arrays;

    public class Demo07_字符高效流特有功能 {

    public static void main(String[] args) throws IOException{

           BufferedReader br = new BufferedReader(

            new FileReader("产品.txt"));

           BufferedWriter bw = new BufferedWriter(

            new FileWriter("产品Copy.txt"));

           String s;

           while((s = br.readLine()) != null) {

            String[] arr = s.split("\|");

            System.out.println(Arrays.toString(arr));

            

            bw.write(s);

            bw.newLine();        

           }      

           br.close();

           bw.close();

    }

    }

    2. 转换流

    1. 编码表:

    1) UTF-8 : 万国码表, 一个数字, 一个字母,一个符号, 占有1个字节, 一个中文占有3个字节

    2) GBK : 国标码, 兼容ASCII和所有中文文字, 一个数字, 一个字母,一个符号, 占有1个字节, 一个中文占有2个字节

    1. 修改文件的编码集, Eclipse

      选中指定文件, 鼠标右键-->properties(属性)

      

     

    1. 转换流解决不同编码集乱码问题:

    1) InputStreamReader(InputStream in,String charsetName) : 字节流向字符桥梁

       a : 通过参数in从文件中读取出字节数据

       b : 通过参数charsetName给定的编码表, 将字节通过对应编码表转换成字符

    2) OutputStreamWriter(OutputStream out, String charsetName) : 字符流向字节桥梁

       a : 将字符通过给定的charsetName编码表, 转换成对应字节

       b : 使用out将字节数据写入到文件中

    注意 : 使用转换流资源时,给出的编码集一定要与文件中实际编码保持一致

    代码

    package com.ujiuye.io;

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.IOException;

    import java.io.InputStreamReader;

    import java.io.OutputStreamWriter;

    public class Demo09_转换流解决不同编码集文件读写 {

    public static void main(String[] args) throws IOException{

             // 1. 创建出一个转换流(输入流)

     InputStreamReader isr = new InputStreamReader(

     new FileInputStream("UTF-8.txt"),"UTF-8");

     OutputStreamWriter osw = new OutputStreamWriter(

     new FileOutputStream("GBK.txt"), "GBK");

     int len;

     while((len = isr.read()) != -1) {

     osw.write(len);

     }

     osw.close();

     isr.close();

    }

    }

    3. IO流异常标准处理方式(扩展)

    JDK1.7版本, 针对IO流异常处理有了新的异常处理语法结构:

    try(

        需要创建IO流资源;

    ){

        IO流使用过程;

    }catch(异常类型 对象名){

        异常处理方式;

    }

    1) 将需要创建的IO流资源创建过程,写入到try小括号中

    2) try大阔号中, 写入可能发生问题的代码

    3) catch一样匹配和捕获异常

    4) 优势 : 当流资源使用完毕, 不需要手动关闭流资源, try小括号自动再留资源 使用完毕之后进行关闭, 并且处理关闭流资源异常情况

    最标准的异常处理方式

    package com.ujiuye.io;

    import java.io.FileInputStream;

    import java.io.FileNotFoundException;

    import java.io.FileOutputStream;

    import java.io.IOException;

    public class Demo10_IO流中异常标准处理方式 {

    public static void main(String[] args) {

           // 1. 为了在finally中关闭资源, 变量可以使用, 提高变量的作用范围

    FileInputStream fis = null;

    FileOutputStream fos = null;

             try {

    fis = new FileInputStream("a\中文.txt");

    fos = new FileOutputStream("中文Cpoy.txt");

    int len;

    while((len = fis.read()) != -1) {

    fos.write(len);

    }

    } catch (FileNotFoundException e) {// ctrl + t : 能查看当前类型继承关系

    e.printStackTrace();

    } catch (IOException e) {

    e.printStackTrace();

    }finally {

    try {

                    // 2. 关闭资源也会有异常,需要try...catch处理, 但因为fos初始值为null,

                    // 因此, 验证fos不为null再关闭流资源

    if(fos != null) {

    fos.close();

    }

    } catch (IOException e) {

    e.printStackTrace();

    }finally {

    try {

                        // 3. fis关闭资源的方式与fos一致

    if(fis != null) {

    fis.close();

    }

    } catch (IOException e) {

    e.printStackTrace();

    }

    }

    }

    }

    }

    JDK7异常新语法处理IO流异常

    package com.ujiuye.io;

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.IOException;

    public class Demo11_IO流异常全新处理方式 {

    public static void main(String[] args) {

             try(

             FileInputStream fis = new FileInputStream("a\中文.txt");

             FileOutputStream fos = new FileOutputStream("中文Cpoy.txt");

             ){

              int len;

       while((len = fis.read()) != -1) {

      fos.write(len);

       }

             }catch(IOException e) {

              e.printStackTrace();

             }        

             System.out.println("over代码结束");

    }

    }

    4. 多线程

    4.1 多线程相关概念

    1. 程序 : 就是一系列数据和逻辑结合体, 例如 : 写出java文件,就是程序
    2. 进程 : 正在内存中运行程序,称为进程
    3. 线程 : 进程(正在运行代码), 需要有代码的独立执行通道, 代码独立执行通道称为线程,

       线程代码执行通道彼此之间互相独立, 如果程序中有多条代码的执行通道, 称程序为多线程程序

      举例 : 例如main方法, 本身就是一条线程, 表示程序中代码的执行通道, 代码经过执行通道才能运行

     

    1. 并行 : 如果多个程序要求同时执行, 硬件完全支持, 效果让多个程序同时都在执行

       举例 : 饭店, 客户, 点了5道菜, 5个厨师每一个人炒一道菜, 5道菜同时在炒

    1. 并发 : 如果多个程序要求同时执行, 硬件设备不能完全支持, CPU处理程序速度非常快, 于是CPU在多个程序之间来回切换执行, 感受不到CPU对于程序切换执行

       举例 : 饭店, 客户, 点了5道菜, 1个厨师, 架起5口锅, 1个厨师在5个菜中来回翻炒

    注意 :  多线程代码运行都是并发执行机制, 因此多线程程序执行具有很大随机性

    4.2 多线程的实现方式

    4.2.1 继承Thread

    1. Thread线程类介绍:

      

     

    1. 多线程实现步骤:

    1) 自定义出一个类, Thread类作为自定义类的直接父类, 于是自定义类也是线程类

    2) 重写Thread父类中的run方法功能, 将需要独立运行的代码设计在run方法中

    3) 创建一个自定义线程类对象

    4) 调用从父类Thread继承来的start方法功能:

       start() :

       a : 开启一个线程

       b : 在独立线程通道中, JVM虚拟机主动调用运行当前线程的run方法

      注意 : 每一个线程类对象只能开启一次

    代码

    package com.ujiuye.thread;

    // 1. 自定义出一个类, Thread类作为自定义类的直接父类, 于是自定义类也是线程类

    public class MyThread extends Thread {

    // 2. 重写Thread父类中的run方法功能, 将需要独立运行的代码设计在run方法中

     @Override

         public void run() {

           for(int i = 1; i <= 10; i++) {

           System.out.println("run---" + i);

           }

         }

    }

    package com.ujiuye.thread;

    public class TestThread {

    // main方法本身就是一条线程

    public static void main(String[] args) {

              // 除了main方法线程之外, 还需要额外的, 独立线程通道

      // 3. 创建一个自定义线程类对象

      MyThread my = new MyThread();

      // 4. 调用从父类Thread继承来的start方法功能,开启线程

      my.start();

      

      // main方法线程中,设计出循环

      for(int i = 1; i <= 10; i++) {

      System.out.println("main---" + i);

      }

     }

    }

    4.2.2 实现Runnable接口

    1. Thread线程类就是Runnable的一个实现类, Runnable是实现一个线程接口
    2. 多线程实现步骤:

    1) 自定义出一个类, 实现Runnable接口

    2) 重写Runnable中唯一方法功能run , 将需要独立运行代码设计到run

    3) 创建出一个自定义线程类对象

    4) 借助Thread线程类中构造方法, Runnable实现类对象封装在一个Thread类型中

       Thread(Runnable run) ;

    5) 借助封装后的Thread类型对象,调用start方法功能:

       a : 开启一个独立线程通道

       b : 运行就是构造参数中的Runnable实现类中的run方法功能  

    代码

    package com.ujiuye.thread;

    public class MyThread2 implements Runnable {

    @Override

    public void run() {

    for(int i = 1; i <= 10; i++) {

    System.out.println("runnable---"+i);

    }

    }

    }

    package com.ujiuye.thread;

    public class TestThread {

    // main方法本身就是一条线程

    public static void main(String[] args) {

              // 除了main方法线程之外, 还需要额外的, 独立线程通道

      // 3. 创建一个自定义线程类对象

      MyThread my = new MyThread();

      // 4. 调用从父类Thread继承来的start方法功能,开启线程

      my.start();   

      

      // 使用Runnable接口实现方法创建出一个独立线程通道

      MyThread2 my2 = new MyThread2();

      Thread t = new Thread(my2);

      t.start();

      

      // main方法线程中,设计出循环

      for(int i = 1; i <= 10; i++) {

      System.out.println("main---" + i);

      }

     }

    }

    4.2.3 匿名内部类实现多线程

    1. 匿名内部类 : 本质就是一个类的子类或者是一个接口的实现类
    2. new 父类或者父接口(){

          // 大括号就表示父类的子类或者接口实现类, 实现过程

    }

    整体语法结构, 相当于创建出一个匿名内部类对象

    代码

    package com.ujiuye.thread;

    public class Demo02_匿名内部类对象实现多线程 {

        // 1. main方法本身就是一个线程

    public static void main(String[] args) {

    // 定义出一个线程

             new Thread() {

              @Override

              public void run() {

              for(int i = 1; i <= 100; i++) {

              System.out.println("线程1---"+ i);

              }

              }

             }.start();

             

             new Thread() {

              @Override

              public void run() {

              for(int i = 1; i <= 50; i++) {

              System.out.println("线程2---"+ i);

              }

              }

             }.start();

             

             new Thread() {

              @Override

              public void run() {

              for(int i = 1; i <= 10; i++) {

              System.out.println("线程3---"+ i);

              }

              }

             }.start();

             

             for(int i = 1; i <= 10; i++) {

              System.out.println("main---" + i);

             }

    }

    }

  • 相关阅读:
    编辑距离算法详解:Levenshtein Distance算法
    直方图均衡化
    Dev之ChartControl控件(二)— 绘制多重坐标图形
    SVM支持向量机算法
    Dev之ChartControl控件(一)
    KNN邻近分类算法
    广州.NET微软技术俱乐部提技术问题的正确方式
    .NET微软技术 开源项目建设
    广州.NET微软技术俱乐部与其他技术群的区别
    广州.NET微软技术俱乐部 微信群有用信息集锦
  • 原文地址:https://www.cnblogs.com/masterhxh/p/13629010.html
Copyright © 2011-2022 走看看