一、IO
1、基本概念
概述:Java的核心库java.io提供了全面的IO接口。包括:文件读写,标准设备输出等。Java中IO是以流为基础进行输入输出的,所有数据被序列化写入输出流,或者从输入流读入
通过数据流、序列化和文件系统提供系统输入和输出
1.1 流
- 流是一个很形象的概念,当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数据源可以是文件,内存,或者是网络连接。类似的,当程序要写入数据的时候,就会开启一个通向目的地的流。这时候你可以想象数据好像在这其中流动一样,当然流动的前提数据要实现序列化。
- 流只能单向流动
- 输入流用来读取in
- 输出流用来写out
- 数据只能从头到尾顺序读写一次
1.2 序列化和反序列化
- 序列化(Serialization)是将对象的状态转换为可以存储或者可以传输的形式的过程,在序列化期间,对象将其状态写入到临时或者持久性存储区。以后可以通过存储区读取或反序列化对象的状态,重新创建该对象。
目的:
- 以某种存储心事使自定义对象持久化;
- 将对象从一个地方传递到另一个地方
- 式程序更具维护性
1.2.1 如何实现序列化
- 实现Serializable或者Externalizable,将java对象序转换为一个字节序列,并能够在以后通过这个字节序列完全恢复为原来的对象。对象的序列化时基于字节,不能使用io流中以字符流读取操作的Reader和Writer
- 静态变量不能被序列化
Externalizatble和Serializable实现序列化的比较:
- Serizalizble是标识接口,实现该接口不用重写任何的方法,将对象中的非transient关键修饰的和非static修饰的属性进行序列化;也可以编写readObject和WriteObject完成部分属性的序列化
- Externalizable接口序列化需要重写writeExternal和readExternal方法,并且在方法中编写相关的逻辑完成序列化和反序列化。此外,通过Externalizatble接口数显序列化必须要有默认的无参构造函数,如果没有,反序列化会报错“no valid constructor”
1.2.2 如何实现反序列化
- 反序列化能将字节序列恢复为原来的对象,,这一过程甚至能通过网络进行,这意味者序列化机制能自动弥补不同操作系统之间的差异
- 通过字节输入流InputStream和它的子类就是实现反序列化
1.3 Java流输入输出原理
Java把这些不同来源和目标的数据同一抽象为数据流,Java语言的输入输出功能是十分强大而灵活的,美中不足的是看上去输入输出的代码并不是很简洁,因为机往往需要包装许多不同对象。
Java类库中,IO部分的类容是很庞大的,因为它书记的领域很广泛:标准输入输出,文件的操作,网上的数据流,字符流,对象流,zip文件流
1.3.1 java流的分类
- 按流向分:
输入流:程序可以从中读取数据流的数据
输出流:程序能向其中写入数据的流- 按数据传输单位分
字节流:以字节为单位传输数据的流
字符流:以字符为单位传输数据的流- 按功能分
节点流:用于直接操作目标设备的流
过滤流:对一个已存在的流的链接和封装,通过对数据进行处理,为程序提供功能强大、灵活的读写功能
2、File文件流
2.1 概述
- 封装一个磁盘路径字符串,让其变为一个对象,对这个对象进行一些方法操作。
- 可以封装文件路径,文件夹(目录)路径,不存在路径(用于自定义创建文件或者目录);
2.2 创建对象
- 通过构造器==>new File(String Path);
2.3 常用方法
- 文件、文件夹(目录)属性。
返回值 | 方法 | 作用 |
long | length() | 返回此抽象路路径表示的文件的字节量 |
boolean | exists() | 测试此抽象路径名表示的文件或目录是否存在。 |
boolean | isFile() | 测试此抽象路径名表示的文件是否是一个标准文件。 |
boolean | isDirectory() | 测试此抽象路径名表示的文件是否是一个目录 |
String | getName() | 返回由此抽象路径名表示的文件或目录的名称。 |
String | getParent() | 返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null |
String | getAbsolutePath() | 返回此抽象路径名的绝对路径名字符串。 |
- 创建、删除
返回值 | 方法 | 作用 |
boolean | createNewFile() | 当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件。 |
boolean | mkdirs() | 新建多层不存在的文件夹\a\b\c |
boolean | mkdir() | 新建单层不存在的文件夹\a |
boolean | delete() | 删除此抽象路径名表示的文件或空的目录,如果目录不为空则无法删除。 |
- 文件夹列表
返回值 | 方法 作用 | |
String[] | list() | 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。 |
File[] | listFiles() | 返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。 |
通过new File(“路径”),将指定路径的目录或者是文件转换会对象,这样就可以调用这个对象所具有的方法,进行输入流操作
3、字节流
3.1 流的继承关系
3.2 字节流读取
- 概念
字节流是由字节组成,字符流是由字符组成的,Java里字符由两个字节组成,字节流是最基本的
,所有InputStream和OutputStream的子类都是,只要用在处理二进制数据。
流式传输主要指将整个音频和视频及三维媒体等多媒体文件经过特定的压缩方式解析成一个个压缩包,由视频服务器向用户计算机顺序或实时传送。在采用流式传输方式的系统中,用户不必像采用下载方式那样等到整个文件全部下载完毕,而是只需经过几秒或几十秒的启动延时即可在用户的计算机上利用解压设备对压缩的A/V、3D等多媒体文件解压后进行播放和观看。此时多媒体文件的剩余部分将在后台的服务器内继续下载。
也就是所谓的在线播放的实现
3.2.1 InputStream抽象类
- 此抽象类是表示字节输入流的所有类的超类,同时也是一个抽象类(不是接口)
- 常用方法:
返回值 | 方法 | 作用 |
abstract int | read() | 从输入流中读取数据的下一个字节。 |
int | read(byte[] b) | 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。 |
int | (byte[] b, int off, int len) | 输入流中将指定 byte 数组中从偏移量 off 开始的 len 个字节读入。 |
void | close() | 关闭此输入流并释放与该流关联的所有系统资源。 |
void | mark(int readlimit) | 在此输入流中标记当前的位置。 |
void | reset() | 将此流重新定位到最后一次对此输入流调用 mark 方法时的位置。 |
3.2.2 FileInputStream子类
- 1、作用:
- 直接插在文件上,直接读取文件数据。
- FileInputStream从文件系统中的某个文件中获取输入字节。哪些文件可取决于主机环境。
- FileInputStream用于读取诸如图像数据之类的原始字节流
- 2、创建对象:
创建方式 | 功能 |
new FIleInputStream(File file) | 通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。 |
FileInputStream(String name) | 通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。 |
- 3、常用方法:参考Input’sStream的常用方法
3.2.3 BufferInputStream子类
- 1、作用:
BufferedInputStream 为另一个输入流添加一些功能,即缓冲输入以及支持 mark 和 reset 方法的能力。在创建 BufferedInputStream 时,会创建一个内部缓冲区数组。在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节。mark 操作记录输入流中的某个点,reset 操作使得在从包含的输入流中获取新字节之前,再次读取自最后一次 mark 操作后读取的所有字节。
是不是想到了看视频时的缓存
- 2、创建对象:
创建方式 | 功能 |
new BufferedInputStream(InputStream in) | 创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。 |
new BufferedInputStream(InputStream in, int size) | 创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用 |
- 3、常用方法:参考Input’sStream的常用方法
3.3 字节流写出
3.3.1 OutputStream抽象类
- 此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节流发送到某个接收器
- 常用方法:
返回值 | 方法 | 作用 |
void | write(byte[] b) | 将 b.length 个字节从指定的 byte 数组写入此输出流 |
void | write(byte[] b, int off, int len)) | 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。 |
abstract void | write(int b | 将指定的字节写入此输出流 |
void | close() | 闭此输出流并释放与此流有关的所有系统资源。 |
void | flush() | 刷新此输出流并强制写出所有缓冲的输出字节。 |
注意
输入流和输出流相比,输出流显得更加重要,通俗点说,输入流就像是在读取数据,数据读取不了可以换一种方式或者刷新,毕竟数据仍然在那里,输出流就像存数据,一旦数据存入失败,可能会真的丢失,因此输出流才会比输入流多一个flush()的方法,不关闭流,只是刷新,并且将数据强制写出,而不是释放
3.3.2 FileOutputStream子类
- 1、作用:
文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流。文件是否可用或能否可以被创建取决于基础平台。特别是某些平台一次只允许一个 FileOutputStream(或其他文件写入对象)打开文件进行写入。在这种情况下,如果所涉及的文件已经打开,则此类中的构造方法将失败。
FileOutputStream 用于写入诸如图像数据之类的原始字节的流。
直接插在文件上,直接写出文件数据
- 2、创建对象:
对象创建方式 | 功能 |
new FileOutputStream(File file) | 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。 |
new FileOutputStream(String name, boolean append) | 创建一个向具有指定 name 的文件中写入数据的输出文件流。true或false决定是否追加 |
- 3、常用方法:参考Output’sStream的常用方法
3.3.3 BufferedOutputStream子类
是FileOutputStream的子类
- 1、作用 :
该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。
可以处理多次多方输入,但总数据只有一个或者只一次性存储的数据,类似于投票
- 2、创建对象:
对象创建方式 | 功能 |
new BufferedOutputStream(OutputStream out | 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。 |
new BufferedOutputStream(OutputStream out, int size) | 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。 |
- 3、常用方法:参考Output’sStream的常用方法
3.4 IO字节流实例
盘F盘中指定的目录存入数据,并且
public class test1112 {
@Test
public void test1() throws IOException {
countfile();
readInputStream();
}
public void countfile() throws IOException {
//boolean newFile = new File("F:\\test\\a.txt").createNewFile();
OutputStream out = new FileOutputStream(new File("F:\\test\\h.txt"));
byte a[]={1,2,3,4,5,6,7,8,9};
out.write(a);
out.close();
}
public void readInputStream () throws IOException {
FileInputStream in = new FileInputStream("F:\\test\\h.txt");
int i=0;
int len =0;
StringBuilder stringBuilder = new StringBuilder();
while (true){
len = in.read();
if (len==-1)break;
stringBuilder.append(len+" ");
}
System.out.println(stringBuilder);
}
}
这里流里面的数据不能用多个read方法去读,因为一个流取出的数据只有一次,读一个少一个,如果有多个read()方法,会造成每个read读取的数据会有丢失,当数据读取完之后再去读到空数据会返回-1
4、字符流读取
- 字符流常用于读取纯文本类型数据
- 输入流
4.1 Reader抽象类
4.1.1 创建对象
创建方式 | 功能 |
protectted Reader() | 创建一个新的字符流reader,其重要部分将同步其自身的reader |
protectec Reader(Object lock) | 创建一个新的字符流reader,其重要部分将同步给定的对象 |
4.1.2 常用方法
返回值 | 方法 | 功能 |
int | read() | 读取单个字符 |
int | read(char[] cbuf) | 将字符读入数组。 |
abstract int | read(char[] cbuf, int off, int len) | 将字符读入数组的某一部分。 |
int | read(CharBuffer target) | 试图将字符读入指定的字符缓冲区。 |
abstract void | void close() | 关闭该流并释放与之关联的所有资源。 |
void | mark(int readAheadLimit) | 标记流中的当前位置。 |
void | reset() | 重置该流,定位到标记位置与mark有关 |
4.2 FileReader子类(继承于InputStreamReader)
- 用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要自己指定这些值,可以先在 FileInputStream 上构造一个 InputStreamReader
4.2.1 创建对象
创建方式 | 功能 |
new FileReader(File file) | 在给定中读取数据的File的情况下创建一个新的FileReader |
new FileReader(String fileName | 在给定从中读取数据的文件名的情况下创建一个新的FileReader |
4.2.2 常用方法
参考Reader抽象类的方法
4.3 BufferedReader子类
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
4.3.1 创建对象
创建方式 | 功能 |
new BufferedReader(Reader in) | 创建一个使用默认大小输入缓冲区的缓冲字符输入流。 |
BufferedReader(Reader in, int sz | 创建一个使用指定大小输入缓冲区的缓冲字符输入流。 |
4.3.2 常用方法
参考Reader抽象类的方法
- 输字符流写出
4.4 Writer抽象类
- 写入字符流的抽象类。子类必须实现的方法仅有 write(char[], int, int)、flush() 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能
4.4.1 创建对象
创建方式 | 功能 |
new Writer() | 创建一个新的字符流 writer,其关键部分将同步 writer 自身。 |
new Writer(Object lock) | 创建一个新的字符流 writer,其关键部分将同步给定的对象。 |
4.4.2 常用方法
返回值 | 方法 | 功能 |
void | write(char[] cbuf) | 写入字符数组。 |
abstract void | write(char[] cbuf, int off, int len) | 写入字符数组的某一部分。 |
void | write(int c) | 写入单个字符。 |
void | write(String str) | 写入字符串。 |
void | write(String str, int off, int len) | 写入字符串的某一部分。 |
Writer | append(char c) | 将指定字符添加到此 writer。 |
abstract void | close() | 关闭此流,但要先刷新它。 |
abstract void | flush() | 刷新该流的缓冲。如果该流已保存缓冲区中各种 write() 方法的所有字符,则立即将它们写入预期目标。然后,如果该目标是另一个字符或字节流,则将其刷新。因此,一次 flush() 调用将刷新 Writer 和 OutputStream 链中的所有缓冲区。 |
4.5 FileWriter子类
- 用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。要自己指定这些值,可以先在 FileOutputStream 上构造一个 OutputStreamWriter。
4.5.1 创建对象
创建方式 | 功能 |
new FileWriter(File file) | 根据给定的 File 对象构造一个 FileWriter 对象。 |
new Writer(Object lock) | 创建一个新的字符流 writer,其关键部分将同步给定的对象。 |
4.5.2 常用方法
参考 Writer
4.6 OutputStreamWriter子类
- OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集
4.6.1 创建对象
创建方式 | 功能 |
new OutputStreamWriter(OutputStream out) | 创建使用默认字符编码的 OutputStreamWriter。 |
new OutputStreamWriter(OutputStream out, String charsetName) | 创建使用指定字符集的 OutputStreamWriter。 |
4.6.2 常用方法
void | close() | 关闭此流,但要先刷新它。 |
void | flush() | 刷新该流的缓冲。 |
String | getEncoding() | 返回此流使用的字符编码的名称。 |
void | write(char[] cbuf, int off, int len) | 写入字符数组的某一部分。 |
void | write(int c) | 写入单个字符 |
void | write(String str, int off, int len) | 写入字符串的某一部分。 |
4.7 BufferedWritter子类
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。
4.71 创建对象
创建方式 | 功能 |
new BufferedWriter(Writer out) | 创建一个使用默认大小输出缓冲区的缓冲字符输出流。 |
new BufferedWriter(Writer out, int sz) | 创建一个使用给定大小输出缓冲区的新缓冲字符输出流。 |
4.7.2 常用方法
参考Writer抽象类
4.8 字符流测试
public class test1113 {
@Test
public void test1() throws IOException {
test2();
test3();
}
public void test2() throws IOException {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("F:\\test\\a.txt"), "UTF-8"));
for(int i=0;i<100;i++){
bw.write(i);
}
FileWriter fileWriter = new FileWriter("F:\\test\\b.txt");
fileWriter.write("进行一个字符流测试");
bw.close();
fileWriter.close();
}
public void test3()throws IOException{
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream("F:\\test\\a.txt")));
Integer read =0;
for (int i=0;(read=bufferedReader.read())!=-1;i++){
System.out.println(read);
}
FileReader fileReader = new FileReader("F:\\test\\b.txt");
int len=0;
char [] arr=new char[20];
while ((len=fileReader.read(arr))!=-1){
System.out.println(Arrays.toString(arr));
}
fileReader.close();
bufferedReader.close();
}
}
二、BIO、NIO和AIO
关于这三个的相关知识,因为实力的原因,讲不好