Java17--IO2
1 字节流写出
1.1 OutputStream抽象类
此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器。
常用方法:
void close()
关闭此输出流并释放与此流有关的所有系统资源。
void flush()
刷新此输出流并强制写出所有缓冲的输出字节。
void write(byte[] b)
将 b.length 个字节从指定的 byte 数组写入此输出流。
void write(byte[] b, int off, int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
abstract void write(int b)
将指定的字节写入此输出流。
1.2 FileOutputStream子类
直接插在文件上,直接写出文件数据
创建对象:
FileOutputStream(String name)
创建一个向具有指定名称的文件中写入数据的输出文件流。FileOutputStream(File file)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(File file, boolean append) –追加
创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
1.3 BufferedOutputStream子类
该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。
创建对象
BufferedOutputStream(OutputStream out)
创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
2 字符流写出
2.1 Writer抽象类
写入字符流的抽象类。
常用方法:
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)
写入字符串的某一部分。
abstract void close()
关闭此流,但要先刷新它。
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)
创建一个使用默认大小输出缓冲区的缓冲字符输出流。
3 练习:文件的写出
把数据写出到指定文件中。如果文件不存在会自动创建,文件夹不存在会报错。
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();
}
}
4 IO综合练习
4.1 练习1:文件复制
from,to。读取from的数据。写出到to文件里
package cn.tedu.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
//文件复制
public class Test4_Copy {
public static void main(String[] args) throws Exception {
// 1,创建读取文件和写出文件
File from = new File("D:\\teach\\a\\1.txt");
File to = new File("D:\\teach\\a\\to.txt");
//调用copy完成文件复制
copy(from, to);
}
//封装了文件复制的工具,将来可以通过类名.直接调用
public static void copy(File from, File to) throws Exception {
// 2,读取from,写出到to
InputStream in = new FileInputStream(from);
OutputStream out = new FileOutputStream(to);
// 3,开始读,读到-1为止
int b = 0;// 记录每次读取到的数据
while ((b = in.read()) != -1) {
out.write(b);// 把读到的内容写出去
}
// 4,关闭资源
in.close();
out.close();
}
}
4.2 练习2:批量读写
package cn.tedu.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
//文件复制
public class Test4_Copy {
public static void main(String[] args) throws Exception {
// 1,创建读取文件和写出文件
File from = new File("D:\\teach\\a\\1.txt");
File to = new File("D:\\teach\\a\\to.txt");
copyByte(from, to);// 一个字节一个自己的复制
copyArray(from, to);// 一个数组一个数组的复制
}
// 一个数组一个数组的复制
private static void copyArray(File from, File to) throws Exception {
// 2,读取from,写出到to
InputStream in = new FileInputStream(from);
OutputStream out = new FileOutputStream(to);
// 3,批量的读和写
int b = 0;// 记录每次读取到的数据
//源码:数组默认的长度一般是8M数组的长度就是8*1024
byte[] bs = new byte[8*1024];//用来缓存数据
while ((b = in.read(bs)) != -1) {//读取数组中的内容
out.write(bs);// 把读到的数组里的内容写出去
}
// 4,关闭资源
in.close();
out.close();
}
// 封装了文件复制的工具,将来可以通过类名.直接调用
public static void copyByte(File from, File to) throws Exception {
// 2,读取from,写出到to
InputStream in = new FileInputStream(from);
OutputStream out = new FileOutputStream(to);
// 3,开始读,读到-1为止
int b = 0;// 记录每次读取到的数据
while ((b = in.read()) != -1) {
out.write(b);// 把读到的内容写出去
}
// 4,关闭资源
in.close();
out.close();
}
}
5 序列化 / 反序列化
5.1 概述
序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。
在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
序列化:利用ObjectOutputStream,对象的信息,按固定格式转成一串字节值输出并持久保存到磁盘化。
反序列化:利用ObjectInputStream,读取磁盘中序列化数据,重新恢复对象。
5.2 特点/应用场景
1、 需要序列化的文件必须实现Serializable接口以启用其序列化功能。
2、 不需要序列化的数据可以被修饰为static的,由于static属于类,不随对象被序列化输出。
3、 不需要序列化的数据也可以被修饰为transient临时的,只在程序运行期间,在内存中存在不会被序列化持久保存。
4、 在反序列化时,如果和序列化的版本号不一致时,无法完成反序列化。
5、 每个被序列化的文件都有一个唯一id,如果没有添加编译器会根据类的定义信息计算产生一个版本号。
6、 常用于服务器之间的数据传输,序列化成文件,反序列化读取数据。
7、 常用于使用套接字流在主机之间传递对象。
5.3 ObjectOutputStream
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。
ObjectOutputStream(OutputStream out)
创建写入指定 OutputStream 的 ObjectOutputStream。
void writeObject(Object obj)
将指定的对象写入 ObjectOutputStream。
5.4 ObjectInputStream
ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。
ObjectInputStream(InputStream in)
创建从指定 InputStream 读取的 ObjectInputStream。
Object readObject()
从 ObjectInputStream 读取对象,读取序列化数据。
5.5 练习1:将学生信息序列化至磁盘【序列化】
package cn.tedu.serializable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Test5_Seri {
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);
}
}
//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 + "]";
}
}
6 编码转换流
用来作为桥梁,把字节流转成字符流的桥梁。
用来解决字符流读写乱码问题。
6.1 工具类
OutputStreamWriter:是字节流通向字符流的桥梁
--OutputStreamWriter(OutputStream out, String charsetName)
--OutputStreamWriter(OutputStream out)
InputStreamReader:是字节流通向字符流的桥梁
--InputStreamReader(InputStream in)
--InputStreamReader(InputStream in, String charsetName)
6.2 常见字符编码表
6.3 测试
package cn.tedu.decode;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
//编码转换流的测试
public class Test5_Decode {
public static void main(String[] args) {
// method();//输出的转换流
method2();//读取的转换流
}
private static void method2() {
try {
//1,创建转换对象
//第二个参数可以设置编码表,解决乱码现象
//文件保存时使用的是gbk编码,如果用utf-8就会乱码
// BufferedReader in = new BufferedReader(
// new InputStreamReader(
// new FileInputStream("1.txt"),"utf-8"));//乱码
BufferedReader in = new BufferedReader(
new InputStreamReader(
new FileInputStream("1.txt"),"gbk"));
//2,读取一行数据
String line = in.readLine();//子类BufferedReader的特有方法
System.out.println(line);
//3,释放资源
}catch(Exception e) {
e.printStackTrace();
}
}
private static void method() {
try {
// 1,创建转换流输出对象,OutputStreamWriter是字节流通向字符流的桥梁
//第二个参数可以设置编码表,解决乱码现象
//写出去的文件如果使用了utf-8表,打开时,使用了默认的gbk编码表,就会出现乱码
// OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream("1.txt"), "utf-8");
OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream("1.txt"), "gbk");
// 2,开始写出数据
// 当数据的保存方式和打开方式,使用的不是一张表时,就会出现乱码!!
out.write("大家好,我是渣渣辉");
// TODO 3,释放资源
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
7 拓展
7.1 IO中flush()和close()的区别
7.2 封装释放资源的close()
public static void close(Closeable io) {
if (io != null) {
try {
io.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
7.3 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 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。但目前还不够成熟,应用不多。
7.4 数组和链表区别
List是一个接口,它有两个常用的子类,ArrayList和LinkedList,看名字就可以看得出一种是基于数组实现另一个是基于链表实现的。
数组ArrayList遍历快,因为存储空间连续;链表LinkedList遍历慢,因为存储空间不连续,要去通过指针定位下一个元素,所以链表遍历慢。
数组插入元素和删除元素需要重新申请内存,然后将拼接结果保存进去,成本很高。例如有100个值,中间插入一个元素,需要数组重新拷贝。而这个动作对链表来说,太轻松了,改变一下相邻两个元素的指针即可。所以链表的插入和修改元素时性能非常高。
实际开发就根据它们各自不同的特点来匹配对应业务的特点。业务一次赋值,不会改变,顺序遍历,就采用数组;业务频繁变化,有新增,有删除,则链表更加适合。
7.5 读一行写一行
package game;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.PrintWriter;
//测试
public class aa {
public static void main(String[] args) {
try {
BufferedReader in = new BufferedReader(new FileReader("1.txt"));
String line = in.readLine();
System.out.println(line);//没数据就会读到null
BufferedReader in = new BufferedReader(new FileReader("1.txt"));
PrintWriter out = new PrintWriter("2.txt");
String line;
while ( ( line=in.readLine() ) != null) {
out.println(line);
}
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}