IO流以及装饰模式

简介: Java中字符是采用Unicode标准,Unicode 编码中,一个英文字母或一个中文汉字为两个字节。而在UTF-8中,一个英文或数字占1个字节,一个常用汉字占用3个字节,不常用汉字占用4个字节。

Java中字符是采用Unicode标准,Unicode 编码中,一个英文字母或一个中文汉字为两个字节。

而在UTF-8中,一个英文或数字占1个字节,一个常用汉字占用3个字节,不常用汉字占用4个字节。


字节流操作的单元是数据单元是8位的字节(一个字节),字符流操作的是数据单元为16位的字符(两个字节)(不同的编码操作的字节数不同)。


1.一个字节等于8位(固定)

2.两个字节等于一个字符(和编码有关,在Java中的Unicode是这样的)

3.所以在Java中,一个字符等于16位


在字节流中,一次读取一个字节,而中文本身有两个字节(UTF-8有三个字节),那么把一个字分成三部份来读,肯定会出现乱码(除非你一次读在当前编码汉字所占的字节数),所以用字符流读取汉字则不会出现乱码。


字节流本身没有缓冲区,缓冲字节流相对于字节流,效率提升非常高。而字符流本身就带有缓冲区,缓冲字符流相对于字符流效率提升就不是那么大了。


这篇文章很好讲述了字节流和字符流的东西,我主要是简单了讲述了一下,细节看下面博主的。


【Java基础-3】吃透Java IO:字节流、字符流、缓冲流_云深i不知处的博客-CSDN博客_javaio流


节点流和处理流

1.节点流比较底层,是直接和特定的数据源,就是存放数据的地方(数组,文件,管道,字符串)进行操作的,灵活性比较低。

2.而处理流(包装流),对节点流或者处理流进行包装(更多是节点流),提供比节点流更多的功能,使用了装饰模式(修饰器模式),不会直接和数据源相联系,真正处理数据的还是节点流。

3.比如BufferReader,能对Read的子类进行封装。条件是Reader子类即可 。


装饰模式(理解)

(1)首先有个Reader的基类,在最顶层,是一个抽象类,里面有两个readFile和readString方法,这两个方法是普通方法,不是抽象方法,方法体为空,而不是没有方法体,然后让子类去做。


(2)FileReader类,继承了Reader类,类似一个节点流,直接和底层数据进行交互,只针对文件进行操作,所以只重写了readFile()方法。


(3)StringReader类,继承了Reader类,类似一个节点流,直接和底层数据进行交互,只针对字符串进行操作,所以只重写了readString()方法。


(4)BufferReader类,也继承了Reader类,但是它是处理流,不直接和底层数据做交互,可以针对不同节点流进行操作,里面有私有属性private Reader reader;,且此类的构造方法是传入一个Reader类的对象进去,也就是说只要是Reader的子类都可以被传进来。每个对应对象就有对应类中的方法,创建对象后调用各自类中的方法即可。


(5)然后就可以在BufferReader类自己创建方法,再在方法中调用他们类的方法进行封装即可(进行方法的拓展),比如想用他们底层的方法进行读取,但又想一次读取多次或者加上缓冲。


(6)在主函数中,new一个BufferReader对象,然后调用BufferReader类中的方法即可(如果调用父类Reader里面的方法就是空的,要调用Reader子类中重写的方法)


额外补充一点当然也可以用多态,Reader类只有一个Read()的抽象方法,然后让全部子类去重写,利用不同对象的动态绑定机制,就知道调用的是哪个类的Read()方法了。

333.png

此图来自韩顺平老师IO流课程课件中的图片。


节点流读取和写入数据(需要异常处理)


1.用字节读取和输入(二进制文件)


(1)FileInputStream

从文件中读取英文,数字,二进制文件的数据,如果文件读取完毕,返回-1


(2)FileOutputStream

将数据写到文件中,如果文件不存在,则创建该文件


综合运用:从C盘读取音频或者图片(输入流),再写入到D盘中(输出流)


2.用字符读取和输入(文本文件)


(1)FileReader

从文件中读取文字,英文,读取完毕返回-1


(2)FileWriter

1.将数据写到文件中,如果文件不存在,则创建该文件

2.里面有个write的构造有个,字符串转化为char[]数组,"文件不存在".toCharArray()

3.一定要关闭流close()或者flush(),才能真正的把数据写入到文件,最好用close()

4.底层两个方法都是用FileOutputStream的write方法。


处理流读取和写入数据(需要异常处理)


1.用字节读取和输入(文本文件)


(1)BufferInputStream

读取的时候会返回实际读取的长度,read()方法,读不到会返回-1,用while循环读取二进制文件


(2)BufferOutputStream

用write(byte[],第几位读取,第几位结束)方法写入文件,最后关闭外层处理流即可

但是用这两个方法也可以读取输入文本文件?

可以,但是我还没明白是什么原因。。。


2.用字符读取和输入(二进制文件)


(1)BufferReader

需要一个路径来读取文件,new一个BufferReader对象,构造参数内传一个节点流对象(装饰模式),可以按行读取readLine,如果为null即读取完毕,关闭流,直接调用close外层流(BufferReader)即可,底层其实是调用节点流的close()以此来关闭流。


(2)BufferWriter

写入文件(如果没有这个文件就会创建一个并写入),创建new一个BufferWriter对象,构造参数传new一个FileWriter对象,如果在BufferWriter中需要追加内容,那么在FileWriter的对象中new的过程中加true即可。


处理流读取和写入对象(需要异常处理)

序列化:保存值和数据类型到文件中


反序列化:从文件中恢复值和数据类型到内存中


(1)ObjectInputStream:提供反序列化功能

1.把.dat文件反序列化恢复数据

2.确认反序列化文件的位置

3.new一个ObjectInputStream

4.抛出异常

55.读取文件(读取的顺序要和保存数据的顺序一致


(2)ObjectOutputStream:提供序列化功能

1.oos.writeObject(new Dog("旺财",9));

2.前提Dog类要实现序列化接口,在序列化保存的时候是按这个类的固定格式保存,不会因为后缀是.txt就是txt文件,用记事本打开.dat文件显示的是乱码

3.序列化不保存static和transient修饰的成员

4.你要序列化一个类,但是这个类有个属性没有被序列化会报错(比如new一个没有序列化的自定义类在全局变量中)

5.父类实现序列化,那么继承它的子类也默认实现序列化


标准输入输出流(System.in/out)


(1)System.in

1.表示标准输入 键盘

2.是System类的 public final static InputStream in=null;

3.编译类型是InputStream

4.运行类型是BufferedInputStream(用字节处理输入流来进行输入)(缓冲流)


举例:Scanner scanner =new Scanner(System.in);


String next=scanner.next();


扫描器到键盘上获取内容


(2)System.out

1.表示标准输出 显示器

2.是System类的 public final static PrintStream out=null;

3.编译类型是PrintStream

4.运行类型是PrintStream(用字节处理输出流来进行输入)(打印流)


举例:System.out.println();


转换流(字符处理流)

把一种字节流转换成字符流


一旦操作文本涉及到具体的指定编码表时,必须使用转换流 。


默认情况下,读取文本文件是按照UTF-8来读取,如果文本文件换成了其他编码,则会出现乱码,所以出现了转换流???????


那什么时候转换呢???


当你处理纯文本时,字符流效率更高,并且可以有效解决中文问题


(1)InputStreamReader(输入流)

InputStream包装成Reader(字节输入流——>字符输入流)


构造器中可以传入一个InputStream类的子类,且可以指定编码(Charset参数)


举例:


//此处通过br对象直接利用FileReader对象来调用里面的方法,但是Java默认编码和路径获取的文本编码方式不同的话,则会引起乱码


BufferReader br=new BufferReader(new FlieReader(路径));


//此处起到了一个中间转换的效果,但是同时也处理了文本的编码方式和Java兼容


InputStreamReader isr=new InputStreamReader(new FileInputStream(路径),"gbk")


BufferReader br=new BufferReader(isr);


//可以合在一起


BufferReader br=new BufferReader(new InputStreamReader(new FileInputStream(路径),"gbk"));


(2)OutputStreamWriter(输出流)

OutputStream包装成Writer(字节输出流——>字符输出流)


先把FileOutputStream字节流转换成字符流OutputStreamWriter,再进行指定用XX编码方式进行保存文件


//把FileOutputStream输出字节节点流转换成了OutputStreamWriter输出字符处理流,把保存的编码转换成了gbk码


OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream(路径),"gbk");


打印处理流

它们的构造器都可以传一个文件,Writer的子类,String其中之一。


(1)PrintStream(字节输出处理流)

System.out的返回值就是PrintStream,此时打印的时候System.out.println不指定位置默认输出在显示器上(标准输出)


修改打印流输出的位置

System.setout(new PrintStream(xxx磁盘位置))

System.out.println(“内容”)


(2)PrintWriter(字符输出处理流)


修改打印流输出的位置


PrintWriter printWriter=new PrintWriter(new FileWriter(xxx磁盘位置));


printWriter.print(“内容”);(你写的内容 底层其实是用ASCLL码去传输的)


printWriter.close();


Properties配置文件


是Hashtable的子类,专门用于读写配置文件的集合类


格式:键值对(键=值)


注意:键值对不需要有空格,默认String类型


传统方法获取配置文件(自己定义类)

IP="192.168.0.1"
地址="北京"
电话="12312321312"


BufferedReader br=new BufferedReader(new FileReader("src\\xxx.properties));
String line=" ";
while((line=br.readLine())!=null){
    String[] split=line.split("=");
    if("IP".equals(split[0])){
        System.out.println(split[0]+"值:"+split[1]);
    }
}
br.close();

Properties类获取配置文件

//创建Properties对象
Properties ppt=new Properties();
//加载指定配置文件
ppt.load(new FlieReader("src\\xxx.properties"));
//K-V显示到控制台
ppt.list(System.out);
//根据K获取对应的值(返回字符串)
ppt.getProperty("xxx");

Properties类创建配置文件

//用Properties 类创建一个配置文件Properties 
Properties ppt2=new Properties();
//创建里面的键值对保存到ppt2对象
//如果value有中文,则转化成unicode码值
ppt2.setProperty("charset","UTF-8");
ppt2.setProperty("name","bom");
ppt2.setProperty("hobby","boy");
//把K-V存到文件中(支持传入所有输出流对象)
//第二个参数是注释,就像我这条一样,放在最顶上,#开头
ppt2.store(new FlieOutputStream("xxx"),null);

Properties类修改配置文件


和Hashtable同理,有一个相同Key,Value不同,则会替换。


setProperty()即可替换修改


注意:

try{}和catch{}的变量不互通,需要设置成方法内的局部变量

目录
相关文章
|
3月前
|
设计模式 Java
【八】设计模式~~~结构型模式~~~装饰模式(Java)
文章详细介绍了装饰模式(Decorator Pattern),这是一种对象结构型模式,用于在不使用继承的情况下动态地给对象添加额外的职责。装饰模式通过关联机制,使用装饰器类来包装原有对象,并在运行时通过组合的方式扩展对象的行为。文章通过图形界面构件库的设计案例,展示了装饰模式的动机、定义、结构、优点、缺点以及适用场景,并提供了Java代码实现和应用示例。装饰模式提高了系统的灵活性和可扩展性,适用于需要动态、透明地扩展对象功能的情况。
【八】设计模式~~~结构型模式~~~装饰模式(Java)
|
3月前
|
设计模式 存储 Java
【十】设计模式~~~结构型模式~~~享元模式(Java)
文章详细介绍了享元模式(Flyweight Pattern),这是一种对象结构型模式,通过共享技术实现大量细粒度对象的重用,区分内部状态和外部状态来减少内存中对象的数量,提高系统性能。通过围棋棋子的设计案例,展示了享元模式的动机、定义、结构、优点、缺点以及适用场景,并探讨了单纯享元模式和复合享元模式以及与其他模式的联用。
【十】设计模式~~~结构型模式~~~享元模式(Java)
|
6月前
|
设计模式 存储 Java
[设计模式Java实现附plantuml源码~结构型]实现对象的复用——享元模式
[设计模式Java实现附plantuml源码~结构型]实现对象的复用——享元模式
|
设计模式 Java
java实现23种设计模式-装饰者模式
java实现23种设计模式-装饰者模式
107 0
装饰者模式
装饰者模式
71 0
装饰者模式详解
装饰者模式详解
|
缓存 Java 数据库连接
深入理解装饰者模式
深入理解装饰者模式
156 0
深入理解装饰者模式
IO流的简述
IO流的简述
104 0
IO流的简述
|
存储 设计模式 Java
基础IO流必须掌握
《基础系列》
88 0