1 字节流写出
1.1 OutputStream抽象类
此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器
常用方法:
1.2 FileOutputStream子类
直接插在文件上,直接写出文件数据
创建对象:
1.3 BufferedOutputStream子类
该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统
创建对象
BufferedOutputStream(OutputStream out)
创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
2 字符流写出
2.1 Writer抽象类
写入字符流的抽象类
常用方法:
2.2 OutputStreamWriter子类
OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集
创建对象
OutputStreamWriter(OutputStream out, String charsetName)
创建使用指定字符集的 OutputStreamWriter。
OutputStreamWriter(OutputStream out)
创建使用默认字符编码的 OutputStreamWriter。
2.3 FileWriter子类
用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。要自己指定这些值,可以先在 FileOutputStream 上构造一个 OutputStreamWriter
创建对象
FileWriter(String fileName)
根据给定的文件名构造一个 FileWriter 对象。
FileWriter(String fileName, boolean append)
根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象
2.4 BufferedWriter子类
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。 可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了
创建对象
BufferedWriter(Writer out)
创建一个使用默认大小输出缓冲区的缓冲字符输出流
2.5 案例练习:文件的写出
package cn.tedu.hello;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
public class rr {
public static void main(String[] args) throws Exception {
// method1();//字节写出
method2();//字符写出
}
private static void method2() throws Exception {
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File("D:\\\\teach\\\\a.txt")),"utf-8"));
long s = System.currentTimeMillis();
for(int i = 48 ; i < 1000000; i++) {
out.write(i);
}
s = System.currentTimeMillis() - s;
System.out.println(s + "--");//266
out.close();
}
private static void method1() throws Exception {
long s = System.currentTimeMillis();
OutputStream out = new FileOutputStream(new File("D:\\teach\\a.txt"));
for(int i = 48 ; i < 1000000; i++) {
out.write(i);
}
s = System.currentTimeMillis() - s;
System.out.println(s + "--");//3484
long ss = System.currentTimeMillis();
OutputStream out2 = new BufferedOutputStream(new FileOutputStream(new File("D:\\teach\\a2.txt")));
for(int i = 48 ; i < 1000000; i++) {
out2.write(i);
}
ss = System.currentTimeMillis() - ss;
System.out.println(ss + "==");//54
out.close();
out2.close();
}
}
3 IO综合练习
3.1 文件复制
from,to。读取from的数据。写出到to文件里
3.2 批量读写
4 序列化 / 反序列化
4.1 概述
序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。
在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
序列化:利用ObjectOutputStream,对象的信息,按固定格式转成一串字节值输出并持久保存到磁盘化
反序列化:利用ObjectInputStream,读取磁盘中序列化数据,重新恢复对象
4.2 特点/应用场景
1、 需要序列化的文件必须实现Serializable接口以启用其序列化功能。
2、 不需要序列化的数据可以被修饰为static的,由于static属于类,不随对象被序列化输出。
3、 不需要序列化的数据也可以被修饰为transient临时的,只在程序运行期间,在内存中存在不会被序列化持久保存。
4、 在反序列化时,如果和序列化的版本号不一致时,无法完成反序列化。
5、 每个被序列化的文件都有一个唯一id,如果没有添加编译器会根据类的定义信息计算产生一个版本号。
6、 常用于服务器之间的数据传输,序列化成文件,反序列化读取数据。
7、 常用于使用套接字流在主机之间传递对象。
4.3 ObjectOutputStream
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储
ObjectOutputStream(OutputStream out)
创建写入指定 OutputStream 的 ObjectOutputStream。
void writeObject(Object obj)
将指定的对象写入 ObjectOutputStream
4.4 ObjectInputStream
ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化
ObjectInputStream(InputStream in)
创建从指定 InputStream 读取的 ObjectInputStream。
Object readObject()
从 ObjectInputStream 读取对象,读取序列化数据
4.5 案例练习:将学生信息序列化至磁盘【序列化】
- 准备一个Student类
//1,如果想完成序列化,类必须实现Serializable接口
//只是用来做标记,需要序列化
class Student implements Serializable{
//创建对象用
public Student(String name, int age, String addr) {
this.name = name;
this.age = age;
this.addr = addr;
}
//一般序列化的都是属性
String name = "张三";
int age = 20;
String addr = "成都";
//为了看属性值
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", addr=" + addr + "]";
}
}
- 将学生信息序列化至磁盘
public static void main(String[] args) throws Exception, IOException {
//序列化:就是把java对象保存在磁盘中
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("D:\\teach\\a\\student.txt"));
Student s = new Student("张三",20,"成都");
os.writeObject(s);
os.close();//关闭输出资源
//反序列化:从磁盘读到程序里
ObjectInputStream in = new ObjectInputStream(new FileInputStream("D:\\teach\\a\\student.txt"));
//读到的对象,默认是Object,需要强转成子类
Student s2 = (Student)in.readObject();
System.out.println(s2);
}
5 编码转换流
用来作为桥梁,把字节流转成字符流的桥梁。
用来解决字符流读写乱码问题
5.1 工具类
6 拓展
6.1 IO中flush()和close()的区别
close包含flush功能,但是flush具备刷新完,还可以继续写操作,close执行完了就流关闭了,不能再写入,所以,不能用close来代替flush
6.2 BIO、NIO、AIO的区别
阻塞IO,BIO 就是传统的 java.io 包,它是基于流模型实现的,交互的方式是同步、阻塞方式,也就是说在读入输入流或者输出流时,在读写动作完成之前,线程会一直阻塞在那里,它们之间的调用时可靠的线性顺序。它的有点就是代码比较简单、直观;缺点就是 IO 的效率和扩展性很低,容易成为应用性能瓶颈。
非阻塞IO,NIO 是 Java 1.4 引入的 java.nio 包,提供了 Channel、Selector、Buffer 等新的抽象,可以构建多路复用的、同步非阻塞 IO 程序,同时提供了更接近操作系统底层高性能的数据操作方式。
异步IO,AIO 是 Java 1.7 之后引入的包,是 NIO 的升级版本,提供了异步非堵塞的 IO 操作方式,所以人们叫它 AIO(Asynchronous IO),异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。但目前还不够成熟,应用不多
6.3 数组和链表区别
List是一个接口,它有两个常用的子类,ArrayList和LinkedList,看名字就可以看得出一种是基于数组实现另一个是基于链表实现的。
数组ArrayList遍历快,因为存储空间连续;链表LinkedList遍历慢,因为存储空间不连续,要去通过指针定位下一个元素,所以链表遍历慢
数组插入元素和删除元素需要重新申请内存,然后将拼接结果保存进去,成本很高。例如有100个值,中间插入一个元素,需要数组重新拷贝。而这个动作对链表来说,太轻松了,改变一下相邻两个元素的指针即可。所以链表的插入和修改元素时性能非常高。
实际开发就根据它们各自不同的特点来匹配对应业务的特点。业务一次赋值,不会改变,顺序遍历,就采用数组;业务频繁变化,有新增,有删除,则链表更加适合