JavaSE进阶——Day10-11 随堂小记

JavaSE进阶——Day10-11 随堂小记

IO流中的必须掌握的内容:

  1. Properties

  2. 基础流(字节流、字符流)

  3. 概念:缓冲区(缓冲流的思想)

  4. 编码表(在开发过程中,乱码经常出现) //编码和解码保证使用相同的编码表

    • 编码

      1
      2
      String str = "黑马";
      byte[] buf = str.getBytes();
    • 解码

      1
      2
      3
      4
      byte[] buf = {-21, -13, -38};
      String str = new String(buf);

      String str = new String(buf , "编码表名字");
  5. 使用转换流读写特定编码的文件

  6. 序列化流(概念:序列化)

复习:线程通讯

  • 线程通讯:在A线程运行的过程中,可以去叫醒其他处于”等待状态”的线程

  • 线程通讯,需要使用到:等待唤醒机制

    • 等待:wait()
    • 唤醒:notify()、notifyAll()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    同步代码块(对象锁){
    对象锁.wait();


    对象锁.notify();//唤醒和当前对象锁绑定的其他处于等待状态的线程
    }


    非静态的同步方法(){ //对象锁:this
    this.wait();


    this.notify();
    }

复习:IO流

  • IO流的作用:对磁盘上的文件进行读、写操作
    • 读:把文件中的数据,读取到内存中
    • 写:把内存中的数据,写入到文件中(持久化存储)
  • IO流分类:
    • 字节流
      • 字节输入流:读 //父类:InputStream 常用子类:FileInputStream
      • 字节输出流:写 //父类:OutputStream 常用子类:FileOutputStream
    • 字符流
      • 字符输入流:读
      • 字符输出流:写
  • IO流使用套路:
    1. 创建:创建流对象
    2. 操作:读、写
      • 读:read()
      • 写:write()
    3. 关闭:释放流资源
      • close()

文件复制:

  • 方案1:循环一次读写1个字节数据 (程序性能低)
  • 方案2:循环一次读写多个字节数据(性能高)

读数据的方法:

1
2
3
4
5
6
7
8
9
//一次读取1个字节数据,返回实际读取到的字节数据;读取到文件末尾时返回:-1
int read()


//一次最多读取buf.length个字节数据,把读取到的字节数据存储到buf数组中,并返回实际读取字节数据的个数
//读取到文件末尾时返回:-1
int read(byte[] buf)


在IO体系下,java提供了高效流(提高读写文件的效率)

  • 读文件:BufferedInputStream
  • 写文件:BufferedOutputStream

在IO流中基础流只有两个:字节流、字符流

BufferedInputStream流的创建: 读数据

  • 自己没有读数据的能力,需要依赖字节输入流实现读数据
1
2
3
//构造方法: public  BufferedInputStream( InputStream  is )

BufferedInputStream bis = new BufferedInputStream( new FileInputStream("关联文件") );

BufferedOutputStream流的创建: 写数据

  • 自己没有写数据的能力,需要依赖字节输出流实现读数据
1
2
3
4
5
6
7
8
9
//构造方法: public  BufferedOutputStream( OutputStream  os )

//覆盖写入
BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream("关联文件") );


//追加写入 (构造方法的第二个参数为true)
FileOutputStream fos = new FileOutputStream("关联文件" , true); //追加写入
BufferedOutputStream bos = new BufferedOutputStream( fos );//当前流有具有追加写入能力

Properties

Properties类:

  1. 作为Map集合的子类存在(存储的数据:key、value)
  2. 可以结合IO流使用 (读、写)

Properties类的基本使用:

  1. 作为集合使用
  2. 结合IO流使用

构造方法:

1
Properties prop = new Properties();

常用方法:

1
2
3
4
5
6
7
8
9
10
11
//向Properties集合中存储:key、value
setPorperty(String key , String value)

//根据指定的key,获取Properties集合中对应的value
String getProperty(String key)

//获取Properties集合中所有的key元素
Set<String> stringPropertyNames();

//借用字节输入流,读取配置文件,读取配置文件中的数据会存储到Properties集合中
load(InputStream is )

在开发中,通常会使用到配置文件,而配置文件格式通常分为:

  1. XML文件
  2. properties文件
  3. ….

Properties类的作用:

  • 读取开发中使用的到.properties配置文件
    • properties配置文件中的数据是以key/value形式体现
    • 把properties配置文件中的key,存储到Properties类中的key元素下
    • 把properties配置文件中的value,存储到Properties类中的value元素下

ResourceBundle工具类

  • 作用: 读取项目工程下src目录中的.properties配置文件
1
2
3
4
5
//获取ResourceBundle对象 (必须保证properties配置文件存放在src目录下)
ResourceBundle rb = ResourceBundle.getBundle("properites配置文件名[不包含后缀名]")

//根据给定的key,获取value
String value = rb.getString("key")

递归

什么是递归?

  • 递归是应用于方法上的解决方案:方法自己调用自己

递归 = 递进 + 回归

  • 递进 :前进
  • 回归: 后退

递归的弊端:

  • 当递归调用的方法过多时,会造成栈内存的溢出

  • 解决方案: 队列结构

    1
    2
    3
    4
    5
    6
    7
    8
    1. 获取所有的File对象,存储到集合中
    2. 遍历集合
    判断:是文件
    判断:是否为java文件
    判断:是目录
    存储到集合中

    细节: 从集合中获取一个数据后,该数据在集合中就无用了

回顾上午内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//读写字节数组
int read(byte[] buf); //最多读取buf.length个长度的字节数据,把读取的字节数据存储到buf数组中
//返回实际读取到字节数据的个数,读取到文件末尾返回:-1

//把buf数组中从index开始向后取len个字节数据写入到文件中
void write(byte[] buf , int index , int len)



//字节缓冲流(高效流) 本身不具备读写能力,需要依赖字节流
//读数据:BufferedInputStream
//写数据:BufferedOutputStream
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("关联文件"))

BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("关联文件"))



//读取properties配置文件
方式1:Properties类
方式2:ResourceBundle类

Properties prop = new Properties();
prop.load(new FileInputStream("xxxx.properties"));
String value = prop.getProperty("key")


//xxx.properties必须存放在当前项目工程的src目录下
ResourceBundle rb = ResourceBundle.getBundle("xxxx");//不需要指定后缀名
String vaule = rb.getString("key");

字符流

为什么使用字符流?

  • 针对纯文本文件中的中文数据,进行读写操作

为什么字节流读取中文数据时有:乱码?

  • 答案:编码表

编码表

概念:

  • 编码
    • 把看得懂的数据,变为看不懂的数据
  • 解码
    • 把看不懂的数据,变为看得懂的数据

在进行编码、解码时必须保证使用相同的编码表。

如果编码表不同,会出现:乱码

编码表:

  • 把生活中的数据和计算机中的数据整合在一起,存放在一张表格中
生活中的数据 编码值 计算机中的数据
A 65 01010101001010101
0 48 01010101001011101
a 97 01010101001010111

字符流: 以字符为单位对文件进行读写操作 //读写都是做为字符数据

  • 字符输入流:读
  • 字符输出流:写

字符流可以读取中文的原因:

  • 字符流 = 字节流 + 编码表
    • 底层还是使用字节流读写数据,但是由于指定编码表,那么就可以一次读写2或3个字节数据

字符输出流:java.io.Writer类

  • Writer类是一个抽象类(不能实例化)
  • 常用子类:FileWriter
1
2
3
//创建字符输出流
Writer w = new FileWriter("关联文件"); //覆盖写入
Writer w = new FileWriter("关联文件" , true ); //追加写入

字符流 = 字节流 + 编码表

  • 内置:缓冲区(数组)
1
字符输出流对象.flush();//刷新流(把缓冲区中的数据写入到文件) 

字符输入流:java.io.Reader类

  • 是一个抽象类
  • 常用子类:FileReader
1
Reader r = new FileReader("关联文件");
1
2
3
4
5
//一次读取1个字符数据
int data = r.read(); //data中存储的是字符数据的编码值

//一次读取多个字符数据
int len = r.read( char[] cbuf )//一次最多读取cbuf.length个字符数据,并把读取的字符数据存储到cbuf数组中。 返回实际读取到的字符数据个数。 读取到文件末尾返回:-1

缓冲流(高效流):

  • 字节缓冲流
    • BufferedInputStream:读
    • BufferedOutputStream:写
  • 字符缓冲流(本身不具备读写能力,需要依赖基本的字符流)
    • BufferedReader:读
    • BufferedWriter:写
1
2
3
4
5
6
//字符输入缓冲流
BufferedReader br = new BufferedReader(new FileReader("关联文件"));

//字符输出缓冲流
BufferedWriter bw = new BufferWriter(new FileWriter("关联文件"));//覆盖写入
BufferedWriter bw = new BufferWriter(new FileWriter("关联文件",true));//追加写入

字符缓冲流,提供了特有方法:

1
2
3
4
5
BufferedReader类中特有方法:
String readLine();//一次读取一行数据(以"\r\n"结尾) ,读取到文件末尾时返回:null

BufferedWriter类中特有方法:
void newLine();//写入换行符(跨平台)

转换流

转换流的作用:读写特定编码表的文件

  • FileReader类默认是UTF-8编码表(无法读GBK编码表的文件)

输入流:InputStreamReader

  • 自身没有读数据的能力,需要依赖字节输入流

输出流:OutputStreamWriter

  • 自身没有写数据的能力,需要依赖字节输出流
1
2
3
4
5
6
7
8
9
//InputStreamReader(InputStream 字节输入流, String 编码表名字) 
//创建输入流,并指定关联文件使用的编码表
InputStreamReader isr = new InputStreamReader(new FileInputStream("关联文件"),"GBK");



//OutputStreamWriter(OutputStream 字节输出流, String 编码表名字)
//创建输出流, 并指定关联文件使用的编码表
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("文件"),"GBK");

字符流的工作原理:

  • 利用了转换流实现:字节流和字符流之间的转换