一、IO流概念
1、IO流用于处理设备上数据。
2、流的分类:
1)输入流(读)和输出流(写)。
2)因为处理的数据不同,分为字节流和字符流。(字符流只可以操作字符数据)
3、流的操作方式只有两种:读和写(读、写都会发生IO异常)
二、IO的体系
1、字节流两个基类(基类就是父类):
InputStream(字节输入流) OutputStream(字节输出流)
2、字符流两个基类:
Reader(字符输入流) Writer(字符输出流)
3、io流体系:看顶层(父类共性功能),用底层(子类具体对象)。
4、在这四个体系中,它们的子类,都有一个共性特点:子类名后缀都是父类名,前缀名都是这个子类的功能名称。
5、硬盘上用于存储数据的体现:文件。
1)将内存中的数据弄到硬盘上,要使用输出流FileWriter
2)将硬盘上的数据弄到内存中,要使用输入流FileReader
三、字符流
1、字符流只可以操作字符数据
2、字符流体系:
1)Reader:用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。
|---BufferedReader:从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。 可以
指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
|---LineNumberReader:跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int) 和 getLineNumber(),它们可分别用于设置和获取当前行号。
|---InputStreamReader:是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它
使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
|---FileReader:用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适
当的。要自己指定这些值,可以先在 FileInputStream 上构造一个 InputStreamReader。
|---CharArrayReader
|---StringReader
2)Writer:写入字符流的抽象类。子类必须实现的方法仅有 write(char[], int, int)、flush() 和 close()。
|---BufferedWriter:将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
|---OutputStreamWriter:是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。
它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
|---FileWriter:用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受
的。要自己指定这些值,可以先在 FileOutputStream 上构造一个 OutputStreamWriter。
|---PrintWriter
|---CharArrayWriter
|---StringWriter
3、字符流的缓冲区:
BufferedReader
BufferedWriter
1)缓冲区给给流的操作动作(读写)提高效率
2)读取键盘录入:
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
四、流的操作规律(四个明确)
1,明确源和目的。
源:InputStream Reader 被读取的。
目的:OutputStream Writer 被写入的。
2,处理的数据是否是纯文本的数据?
是:使用字符流。Reader Writer
否:使用字节流。 InputStream OutputStream
如果是源并且是纯文本,Reader
如果是目的并且是纯文本,Writer
3,明确数据所在的设备:
1)源设备:
键盘(System.in)
硬盘(FileXXX)FileReader FileInputStream
内存(数组)ByteArrayInputStream CharArrayReader StringReader
网络(Socket)
2)目的设备:
显示器(控制台System.out)
硬盘(FileXXX)FileWriter FileOutputStream
内存(数组)ByteArrayOutputStream CharArrayWriter StringWriter
网络(Socket)
4,明确是否需要额外功能?
1)是否需要高效?缓冲区Buffered 四个。
2)是否需要转换?转换流 InputStreamReader OutputStreamWriter
3)是否操作基本数据类型? DataInputStream DataOutputStream
4)是否操作对象(对象序列化)? ObjectInputStream ObjectOutputStream
5)需要对多个源合并吗? SequenceInputStream
6)需要保证数据的表现形式到目的地吗? PrintWriter
五、File类
1、专门用于描述系统中文件或者文件夹的对象。
2、可以用于操作文件或者文件夹的属性信息。
3、常用功能:
1)获取文件信息。
获取名称,
获取路径。
获取大小。
获取时间。
...
2)判断。
是只读的不?
是隐藏的不?
3)文件的创建和删除以及该文件是否存在,文件对象自己最清楚。
具体创建,删除,是否存在等功能。
六、递归
1、就是函数自身调用自身(直接或者间接)。递归就是在栈内存中不断的加载同一个函数。
2、什么时候用递归呢?
当一个功能被复用,每次这个功能需要的参数都是根据上一次该功能的元素得出的。
3、递归的注意事项:
1)一定要定义条件。 否则就是StackOverflowError(栈内存溢出异常)
2)一定要递归次数。(次数过多是不行的。(这就是为什么我们删除一个目录层级特别深,体积却不大的文件夹要
删很长时间的原因,因为要递归))
七、Properties(在Java.util包中)
1、 一个可以将键值进行持久化存储的对象。Map接口中Hashtable的子类。
2、 该类上没有泛型定义,因为它的键值都是固定的字符串类型。
3、因为存储都是字符串数据,通常都作为属性信息存在。
4、该集合最大的特点就是可以和IO技术相结合。也就是,该集合中的数据可以来自于流。也可以将集合中的数据写
入到流中。
5、特点:
1)可以持久化存储数据。
2)键值都是字符串。
3)一般用于配置文件。
八、PrintStream(打印流)
1、提供了更多的功能,比如打印方法。可以直接打印任意类型的数据。
2、它有一个自动刷新机制,创建该对象,指定参数,对于指定方法可以自动刷新。
3、它使用的本机默认的字符编码.
4、该流的print方法不抛出IOException。
5、 构造方法:
该流是一个处理目的的流对象。
目的:
1,File对象。 可以指定字符集
2,字符串路径。可以指定字符集
3,字节输出流。可以对println方法进行自动刷新。
6、该对象的构造函数
PrintStream(File file) :创建具有指定文件且不带自动行刷新的新打印流。
PrintStream(File file, String csn) :创建具有指定文件名称和字符集且不带自动行刷新的新打印流。
PrintStream(OutputStream out) :创建新的打印流。
PrintStream(OutputStream out, boolean autoFlush) :创建新的打印流。
PrintStream(OutputStream out, boolean autoFlush, String encoding) :创建新的打印流。
PrintStream(String fileName) :创建具有指定文件名称且不带自动行刷新的新打印流。
九、PrintWriter
1、该对象的目的地有四个:
1)File对象。
2)字符串路径。
3)字节输出流。
4)字符输出流(具备了PrintStream的特点同时,还有自身特点)
2、开发时尽量使用PrintWriter。
3、代码演示:
//读取键盘录入将数据转成大写显示在控制台
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));//源:键盘输入
PrintWriter out = new PrintWriter(new FileWriter("out.txt"),true);//设置true后自动刷新
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
System.out.println(line.toUpperCase());//转大写输出
}
out.close();
bufr.close();
十、SequenceInputStream (序列流)
1、作用就是将多个读取流合并成一个读取流。实现数据合并。
2、适用于文件切割。
3、将多个流进行逻辑串联(进行合并,变成一个流,操作起来很方便,因为多个源变成了一个源)
4、持久化:是把数据放硬盘上。
5、序列化:就是放好多数据,并按顺序放。
6、反序列化:就是把序列化后的文件按照顺序读出来(对象直接从硬盘中取到内存中,并有一个类的字节码文件,
在内存中进行对象的生成)
7、对象的序列化:目的:将一个具体的对象进行持久化,写入到硬盘上。
8、合并原理:多个读取流对应一个输出流。
9、切割原理:一个读取流对应多个输出流。
10、注意:类中的静态数据不会被序列化。
11、非静态数据有些不需要序列化,这就需要一个关键字来完成。transient 瞬间的,暂时的。
十一、Serializable接口
1、这个接口用于给被序列化的类添加一个序列版本号,而且这个版本号还要显示出来。
2、为了判断序列化的对象和对应的class类是否匹配。
3、这个版本号通过类中的成员的数字签名算出来的。
十二、RandomAccessFile(IO包中的工具类)
1、不是字节流或者字符流体系中的成员。
2、该类是用于操作File的类。
3、该对象既可以读取又可以写入。
4、该对象中封装中了一个byte类型的数组。
5、其实它内部就是封装了字节输入流和字节输出流。
6、通过seek方法设置数组的指针就可以实现对文件数据的随机读写。
7、可以实现数据的修改。
8、注意:被操作的数据一定要规律。
十三、管道流
1、管道读取流和管道写入流可以像管道一样对接上,管道读取流就可以读取管道写入流写入的数据。
2、注意:管道流的使用需要加入多线程技术,因为单线程,先执行read,会发生死锁,因为read方法是阻塞式的,
没有数据的read方法会让线程等待。
3、代码演示:
public static void main(String[] args) throws IOException{
PipedInputStream pipin = new PipedInputStream();
PipedOutputStream pipout = new PipedOutputStream();
pipin.connect(pipout);
new Thread(new Input(pipin)).start();
new Thread(new Output(pipout)).start();
}
十四、DataOutputStream、DataInputStream(操作基本数据类型)
1、专门用于操作基本数据类型数据的对象。
2、基本数值的时候,有时候把一些基本类型存起来,存完后读出来就行了,这时候就必须用到操作基本数据类型的
对象
3、代码演示:
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeInt(256);
dos.close();
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
int num = dis.readInt();
System.out.println(num);
dis.close();
十五、ByteArrayInputStream、ByteArrayOutputStream(操作字节数组)
1、ByteArrayInputStream:源:内存
ByteArrayOutputStream:目的:内存。
2、用于操作字节数组的流对象,其实它们就是对应设备为内存的流对象。
3、该流的关闭是无效的,因为没有调用过系统资源。
4、按照流的读写思想操作数组中元素。 (数组在内存里面都是缓冲区)(这里是可变长度的数组)(但是这个数组
里装的东西不能过大,比如DVD)
5、代码演示:
//创建源:
ByteArrayInputStream bis = new ByteArrayInputStream("abcdef".getBytes());
//创建目的:
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int ch = 0;
while((ch=bis.read())!=-1){
bos.write(ch);
}
System.out.println(bos.toString());