一、流的概念
1.流是一个很形象的概念,当程序需要读数据的时候,就会开启一个通向数据源的流,这个数据源可以是文件、内存、网络连接;类似的,当程序需要写入数据的时候,就会开启一个通向目的地的流。
2.Java流的示意图
流这个比喻的本质就是为了让某个对象可以均匀持续地吐出无间隔的数据,或者你可以向这个对象毫无压力地持续不断塞进数据。
二、IO流的分类
1.按照流的流向分,可以分为输入流和输出流
(1)输入流:相对于某一对象,通常外界向对象输入信息叫作输入流(对象接收外界信息的时候需要读取信息)
输出流
(2)输出流:对象向外界输出信息叫作输出流。
总结:对象间进行信息或者数据交换的时候,总是将对象或数据转换成某种形式的流,再通过流的传输到达目的对象后,将流转换为对象数据,所以可以将流看作为是数据的载体,通过流可以实现数据的交换和传输。
2.按照操作单元分,可以划分为字节流和字符流。
字节流与字符流的用法几乎完全一样,区别在于它们锁操作的额数据单元不一样,字节流操作的数据单元是8位的字节;二字符流操作的数据单元是16位的字符。
三、Java输入/输出流体系的分类表
其中:
InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。
四、常见IO流的用法
1.IO流体系的输入流基类(InputStream/Reader)它本身并不能创建实例来执行输入,但它是所有输入流的模板,因此它所具有的方法是所有输入流都可以使用的方法;
InputStrea里面包含的三种方法:
(1)int read();从输入流里面读取单个字节,返回读取的字节数据(字节数据可直接转换为int类型);
(2)int read(byte[]a)从输入流里面最多读取a.length个字节的数据,并将其存放在数组a中,返回实际读取的字节数;
(3)int read(byte[]b,int off,int len);从输入流里面最多读取 len个字节的数据,并将其存储在数组b中,这里并不是从数组起点开始,而是从off位置开始,返回实际读取的字节数。
Reader里面包含的三种方法:
(1)int read();从输入流里面读取单个字符,返回读取的字符数据(字符数据可直接转换成int类型);
(2)int read(char[]a);从输入流里面最多读取a.length个字符的数据,并将其存放在数组a中,返回实际读取的字符数;
(3)int read(char[]b,int off,int len);从输入流里面最多读取len个字符的数据,并将其存放在数组b中,这里并不是从数组起点开始,而是从off位置开始,返回实际读取的字符数。
2.IO流体系的输出流基类(OutputStream/Writer)
连个流都提供了如下三种方法:
(1)void write(int c);将指定的字节/字符输出到输出流中,其中c可以代表字节,也可以代表字符
(2)void write(byte/char[] b);将字节数组/字符数组输出到指定的输出流中;
(3)void write(byte/char[] b,int off,int len);将字节/字符数组中的数据从off位置开始,长度位len的字节/字符输出到输出流中去。
因为字符流直接以字符作为操作单位,所以Writer可以用字符串来代替字符数组,即以String对象作为参数。Writer里面还包含如下两个方法:
void write(String str); 将str字符串里包含的字符输出到指定输出流中。
void write (String str, int off, int len); 将str字符串里面从off位置开始,长度为len的字符输出到指定输出流中。
五、操作系统中的文件
1.文件是由一些具有永久存储及特点顺序的字节组成的一个有序的,具有名称的集合。在Java语言中,用来表示文件的是File类。(对文件的操作实际就是对流的操作)
2.由于InputStream和Reader都是抽象类,本身不能创建实例,所以它们分别有一个文件输入与输出流类(File为设备InputStream或OutputStream为接口规范)
(1)FileInputStream类创建一个能从文件中读取字节的InputStream
(2)FileOutputStream类创建一个可以向文件写入字节的类OutputStream
import java.io.*;
public class TestIO {
/**
*测试文件输出流(对象向外界输出信息即向文件里面写入字节)
*/
@Test
public void test1() throws Exception {
FileOutputStream aa = new FileOutputStream("D:/A流/a.txt");
int a = 12;//00000000 00000000 00000000 00001100
byte[] b = {0,0,0,12};
//用write方法向文件里面写入字节
aa.write(b[0]);
aa.write(b[1]);
aa.write(b[2]);
aa.write(b[3]);
aa.close();//释放流的资源,流用完之后要关掉,否则很浪费资源
}
/**
*测试文件输入流(外界向对象输入信息,需要读取信息)
*/
@Test
public void test2() throws Exception {
FileInputStream aa = new FileInputStream("D:/A流/a.txt");
byte[] b = new byte[4];//最多四个字节的数据读入到一个字节数组b中
b[0] = (byte) aa.read();
b[1] = (byte) aa.read();
b[2] = (byte) aa.read();
b[3] = (byte) aa.read();
System.out.println(b[3]);
aa.close();//释放流的资源,流用完之后要关掉,否则很浪费资源
}
}
输出结果为12,说明已经将数据存入进去了
六、构造对象的输入输出流
(1)再通过对象输入流将对象状态恢复
ObjectInputStream : 对象输入流
ObjectOutPutStream :对象输出流
/**
* 对象流ObjectXXXStream
* @throws Exception
*/
@Test
public void test5() throws Exception {
OutputStream aa = new FileOutputStream("D:/A流/b.txt");
ObjectOutputStream objout = new ObjectOutputStream(aa);
objout.writeInt(24);
objout.writeDouble(9.45);
objout.writeChar('字');
objout.writeBoolean(true);
objout.writeChars("dsfsfdsf");
objout.flush();
aa.close();//释放流的资源,流用完之后要关掉,否则很浪费资源
}
@Test
public void test6() throws Exception {
InputStream aa = new FileInputStream("D:/A流/b.txt");
//装饰模式
ObjectInputStream objin = new ObjectInputStream(aa);//取字节
int ii = objin.readInt();
System.out.println(ii);//对象流转换
double dd = objin.readDouble();
System.out.println(dd);
char cc = objin.readChar();
System.out.println(cc);
boolean ll = objin.readBoolean();
System.out.println(ll);
aa.close();//释放流的资源,流用完之后要关掉,否则很浪费资源
}
@Test
public void test7() throws Exception {
OutputStream aa = new FileOutputStream("D:/A流/b.txt");
ObjectOutputStream objout = new ObjectOutputStream(aa);
Date d = new Date();
objout.writeObject(d);
objout.flush();
aa.close();//释放流的资源,流用完之后要关掉,否则很浪费资源
}
@Test
public void test8() throws Exception {
InputStream aa = new FileInputStream("D:/A流/b.txt");
//装饰模式
ObjectInputStream objin = new ObjectInputStream(aa);//取字节
Date d = (Date)objin.readObject();
System.out.println(d);
aa.close();//释放流的资源,流用完之后要关掉,否则很浪费资源
}
}
(2)Serializable序列化
把对象转换为字节序列的过程称为对象的序列化。
Serializable做标记用,判断对象是否实现序列化,是否可以存起来
当Student没有实现Serializable接口时,会报序列化异常,因此Student需要实现这个接口
import java.io.Serializable;
public class Student implements Serializable {
private int id;
private String name;
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public Student(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}