IO流
1、概念:
I就是Input(输入), O就是Output(输出)
IO流用来处理设备之间的数据传输
Java对数据的操作是通过流的方式
Java用于操作流的类都在IO包中
按流向分为两种:输入流和输出流。在早期时只有字节流,后期为了方便处理不同的文字出现了字符流。
按操作类型分为两种:字节流(通用)与字符流(融合了编码表)。
2、IO流常用基类:
字节流的抽象基类:InputStream ,OutputStream。
字符流的抽象基类:Reader ,Writer。
注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
如:InputStream的子类FileInputStream。
如:Reader的子类FileReader。
InputStreamReader 是字符流, 可以从字节流中读取字符
要创建对应必须通过已知实现子类完成
3、IO程序的书写:
* 导入IO包中的类
* 进行IO异常处理
* 在finally中对流进行关闭
创建流的时候Java虚拟机会和操作系统产生关联, 建立一个程序和文件的连接,如果流使用结束之后,
不释放这个连接, 系统资源会一直占用。
4、拷贝文件
a.逐个字节, 调用FileInputStream.read()和FileOutputStream.write(int)
b.整个文件, 调用FileInputStream.available()方法获取流中的字节个数, 创建一个数组, 调用read(byte[])
方法读取数据, 调用write(byte[])写出
c.小数组, 定义一个适当大小的小数组, 一次拷贝一个数组大小的数据, 把数据写出, 再拷贝一个数组, 循环...
5、路径问题
相对路径: 不以盘符开头. 相对于某个路径, 在不同的环境中指向不同路径, 在Eclipse中运行时相对于工程的根目录.
绝对路径: 以盘符开头. 不论在任何环境下运行, 都是一个绝对的路径.
6、标准化代码
JDK7之前, 我们需要使用try finally代码块来关闭流
JDK7之后, 实现了AutoCloseable的类可以自动关闭
7、字符流:
什么是字符流?
Reader和Writer的子类, 也是一种输入输出流, 它们可以更方便的读写字符.
InputStream和OutputStream虽然也可以读写字符, 但是需要人工编码和解码, 使用Reader和Writer可自动完成。
字符流的父类:
Reader是所有字符输入流的父类
Writer是所有字符输出流的父类
字符流体系常用类:
Reader
|--FileReader:使用默认码表, 从文件中读取字符. 功能和InputStreamReader一样.专门操作文件
|--BufferedReader:对字节输入流进行功能增强,内部有readLine方法,构造函数接收字节输入流对象
|--InputStreamReader:把一个字节输入流转为字符流, 从而读取字符, 内部可以自动解码(读取到字节转为字符)
Writer
|--FileWriter:使用默认码表, 向文件中写入字符. 功能和OutputStreamWriter一样.专门操作文件
|--BufferedWriter:对字节输出流进行功能增强,内部有newLine方法,构造函数接收字节输出流对象
|--OutputStreamWriter:把一个字节输出流转为字符流, 从而写出字符, 内部可以自动编码(写出字符转为字节)
InputStreamReader, OutputStreamWriter:
InputStreamReader和OutputStreamWriter如果不指定码表就会使用当前默认码表来进行编码解码, 如需指定可以
在构造函数中传入码表名
创建文件:
* 创建流对象,建立数据存放文件:FileWriter fw = new FileWriter(“Test.txt”);
* 调用流对象的写入方法,将数据写入流:fw.write(“text”);
* 关闭流资源,并将流中的数据清空到文件中:fw.close();
FileWriter fw = null;
try {
fw = new FileWriter("Test.txt");
fw.write("text");
}
catch (IOException e){
System.out.println(e.toString());
} finally {
if(fw!=null)
try {
fw.close();
} catch (IOException e){
System.out.println(e.toString());
}
}
读取文件:
建立一个流对象,将已存在的一个文件加载进流:FileReader fr = new FileReader(“Test.txt”);
创建一个临时存放数据的数组:char[] ch = new char[1024];
调用流对象的读取方法将流中的数据读入到数组中:fr.read(ch);
FileReader fr = null;
try {
fr = new FileReader("c:\\test.txt");
char[] buf = new char[1024];
int len= 0;
while((len=fr.read(buf))!=-1) {
System.out.println(new String(buf,0,len));
}
} catch (IOException e) {
System.out.println("read-Exception :"+e.toString());
} finally {
if(fr!=null) {
try {
fr.close();
}
catch (IOException e) {
System.out.println("close-Exception :"+e.toString());
}
}
}
注意:
定义文件路径时Windows中的目录符号为“\”,但这个符号在Java中是特殊字符,需要转义。用“\\”或“/”表示。
写出时文件如不存在程序会创建新文件,如文件已存在则会清空原文件内容重新写入。
追加内容可用FileWriter构造函数FileWriter(String fileName, boolean append),传入true不会清空原有文件
读取文件时必须保证文件存在,否则将抛出FileNotFoundException。
字符流的缓冲区:由于单个字符读写需要频繁操作文件,效率非常低。定义缓冲区将要读取或写出的数据缓存,
减少操作文件次数。
缓冲区读取:
先定义一个数组,然后调用FileReader读取一个数组的方法
int read(char[] cbuf)
缓冲区写出:
将要写出的数据存放在数组中,调用FileWriter方法,一次写出一个数组。
void write(char[] cbuf, int off, int len)
内置缓冲区的BufferedReader和BufferedWriter:
Java提供了带缓冲功能的Reader和Writer类:BufferedReader,BufferedWriter
这两个类都是提供包装功能,需要提供其他流来使用,给其他流增加缓冲功能
BufferedReader类提供了一个读取一行的方法readLine(),调用它的read()方法读取数据时,
程序会从文件中一次读取8192个字符用来缓冲。
BufferedWriter类提供了写出一个换行符号的功能newLine()调用它的write()方法写出数据时,
程序会先将数据写出到缓冲数组,直到写满8192个才一次性刷出到文件
* 缓冲区的出现提高了对数据的读写效率。
* 对应类:BufferedWriter、BufferedReader
* 缓冲区要结合流才可以使用。
* 在流的基础上对流的功能进行了增强
装饰设计模式:
什么是装饰设计模式?
在设计类的时候, 发现一个类的功能不够用, 我们可以使用包装设计模式定义一个新的类, 新的类中包装
旧的类进行增强,新的类和旧的类具有相同的方法声明, 但是功能更强大。
装饰模式的基本格式:
* 含有被装饰类的引用
* 通过构造函数传入被装饰类对象
* 和被装饰类含有同样的方法,其中调用被装饰类的方法,对其进行改进、增强
* 和被装饰类继承同一个类或实现同一个接口,可以当做被装饰类来使用
它与继承有什么不同?
装饰设计模式不占用继承的位置
装饰设计模式构造函数中可以传入不同类型的对象, 传入什么对象就对什么对象进行增强
了解BufferedReader的原理:
BufferedReader、BufferedWriter都是装饰类,他们可以装饰一个Reader或Writer,给被装饰的Reader和
Writer提供缓冲的功能。就像我们用BufferedReader、BufferedWriter装饰FileReader和FileWriter,使
用的读写功能还是FileReader和FileWriter的,但给这两个类的读写添加了缓冲功能。
字符流只能拷贝纯文本的文件, 而且在读取的时候会解码, 写出的时候会编码, 效率很低