I/O流技术是用于处理数据传输的。如读/写文件,网络通讯等
java中,对于数据的输入/输出操作以"流(Stream)" 的方式进行
java.io 包下提供各种"流"类和接口
输入流 input 主要是读取
输出流 output 主要是写入
流可以分为:
按单位:字节流(8 bit,二进制的) 和 字符流(按字符)
按数据流:输入流、输出流
按角色:节点流,处理流、包装流
首先一张图,需要牢记![微信图片_20221002225040](https://typora-1257023524.cos.ap-shanghai.myqcloud.com/typora/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20221002225040.png)
抽象基类:
输入字节流:InputStream
输出字节流:OutputStream
输入字符流:Reader
输出字符流:Writer
节点流:节点流是底层的/低级流,直接跟数据源相接
包含如下:
字节输入流:FileInputStream、ByteArrayInputStream、PipedInputStream
filePath = "src\\pic.jpg";
FileInputStream fis = new FileInputStream(filePath);
//首先定义字节数组
//然后定义长度
byte[] buf = new byte[1024];
int readLen = 0;
//while循坏读取
while((readLen = fis.read(buf)) != -1){
System.out.print(new String(buf, 0, readLen));
}
/**
* 使用 read(byte[] b) 读取文件,提高效率
*/
@Test
public void readFile02() {
String filePath = "e:\\hello.txt";
//字节数组
byte[] buf = new byte[8]; //一次读取8个字节.
int readLen = 0;
FileInputStream fileInputStream = null;
try {
//创建 FileInputStream 对象,用于读取 文件
fileInputStream = new FileInputStream(filePath);
//从该输入流读取最多b.length字节的数据到字节数组。 此方法将阻塞,直到某些输入可用。
//如果返回-1 , 表示读取完毕
//如果读取正常, 返回实际读取的字节数
while ((readLen = fileInputStream.read(buf)) != -1) {
System.out.print(new String(buf, 0, readLen));//显示
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭文件流,释放资源.
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
字节输出流:FileOutputStream、ByteArrayOutputStream、PipedOutputStream
filePath = "e:\\a.txt";
FileOutputStream fos = new FileOutputStream(filePath);
fos.write()
ackage com.hspedu.outputstream_;
import org.junit.jupiter.api.Test;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @author 韩顺平
* @version 1.0
*/
public class FileOutputStream01 {
public static void main(String[] args) {
}
/**
* 演示使用FileOutputStream 将数据写到文件中,
* 如果该文件不存在,则创建该文件
*/
@Test
public void writeFile() {
//创建 FileOutputStream对象
String filePath = "e:\\a.txt";
FileOutputStream fileOutputStream = null;
try {
//得到 FileOutputStream对象 对象
//老师说明
//1. new FileOutputStream(filePath) 创建方式,当写入内容是,会覆盖原来的内容
//2. new FileOutputStream(filePath, true) 创建方式,当写入内容是,是追加到文件后面
fileOutputStream = new FileOutputStream(filePath, true);
//写入一个字节
//fileOutputStream.write('H');//
//写入字符串
String str = "hsp,world!";
//str.getBytes() 可以把 字符串-> 字节数组
//fileOutputStream.write(str.getBytes());
/*
write(byte[] b, int off, int len) 将 len字节从位于偏移量 off的指定字节数组写入此文件输出流
*/
fileOutputStream.write(str.getBytes(), 0, 3);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
字符输入流:FileReader、CharArrayReader、PipedReader
字符输出流:FileWriter、CharArrayWriter、PipedWriter
处理流:包装节点流,既可以消除不同节点流的实现差异,又可以提供更方便的方法来完成输入输出。处理流使用了修饰器设计模式,不会直接和数据源相接。一般使用处理流来完成数据传输,可提高性能,还能操作便捷。
包含如下:
缓冲流:使用带缓冲的输入输出流,效率更高,速度更快,写完数据后,要调用flush()
方法或close()
方法,这样数据才能写入
写入:直接.write()
BufferedWriter bw = new BufferedWriter();
bw.write();
读取:如果是一行直接 输入流对象.read(), 如果循坏读取 首先定义一个字符串 对象用于接收
BufferedReader br = new BufferedReader();
String line;
while((line= br.readline()) != null){
System.out.println(line);
}
字节缓冲流:BufferedInputStream(输入流,读取) 和 BufferedOutputStream(输出流,写入)
字符缓冲流: BufferedReader (输入流,读取) 和 BufferedWriter(输出流,写入)
package com.hspedu.writer_;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
/**
* @author 韩顺平
* @version 1.0
* 演示BufferedWriter的使用
*/
public class BufferedWriter_ {
public static void main(String[] args) throws IOException {
String filePath = "e:\\ok.txt";
//创建BufferedWriter
//说明:
//1. new FileWriter(filePath, true) 表示以追加的方式写入
//2. new FileWriter(filePath) , 表示以覆盖的方式写入
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath));
bufferedWriter.write("hello, 韩顺平教育!");
bufferedWriter.newLine();//插入一个和系统相关的换行
bufferedWriter.write("hello2, 韩顺平教育!");
bufferedWriter.newLine();
bufferedWriter.write("hello3, 韩顺平教育!");
bufferedWriter.newLine();
//说明:关闭外层流即可 , 传入的 new FileWriter(filePath) ,会在底层关闭
bufferedWriter.close();
}
}
package com.hspedu.reader_;
import java.io.BufferedReader;
import java.io.FileReader;
/**
* @author 韩顺平
* @version 1.0
* 演示bufferedReader 使用
*/
public class BufferedReader_ {
public static void main(String[] args) throws Exception {
String filePath = "e:\\a.java";
//创建bufferedReader
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
//读取
String line; //按行读取, 效率高
//说明
//1. bufferedReader.readLine() 是按行读取文件
//2. 当返回null 时,表示文件读取完毕
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
//关闭流, 这里注意,只需要关闭 BufferedReader ,因为底层会自动的去关闭 节点流
//FileReader。
/*
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
try {
in.close();//in 就是我们传入的 new FileReader(filePath), 关闭了.
} finally {
in = null;
cb = null;
}
}
}
*/
bufferedReader.close();
}
}
转换流:一般操作输入输出内容的时候,就需要使用字节或字符流,但是,有些时候,需要将字符流变成字节流形式,或者字节流变成字符流形式。可以用于乱码
OutputStreamWriter(字符输出流) 和 InputStreamReader(字符输入流)
OutputStreamWriter类的构造方法
//OutputStreamWriter(OutputStream out)
//创建使用默认字符编码的 OutputStreamWriter。
//从构造方法可以看出,在outputStreamWriter类中需要一个字节流对象。
package com.hspedu.transformation;
import java.io.*;
/**
* @author 韩顺平
* @version 1.0
* 演示 OutputStreamWriter 使用
* 把FileOutputStream 字节流,转成字符流 OutputStreamWriter
* 指定处理的编码 gbk/utf-8/utf8
*/
public class OutputStreamWriter_ {
public static void main(String[] args) throws IOException {
String filePath = "e:\\hsp.txt";
String charSet = "utf-8";
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePath), charSet);
osw.write("hi, 韩顺平教育");
osw.close();
System.out.println("按照 " + charSet + " 保存文件成功~");
}
}
InputStreamReader类的构造方法也类似
package com.hspedu.transformation;
import java.io.*;
/**
* @author 韩顺平
* @version 1.0
* 演示使用 InputStreamReader 转换流解决中文乱码问题
* 将字节流 FileInputStream 转成字符流 InputStreamReader, 指定编码 gbk/utf-8
*/
public class InputStreamReader_ {
public static void main(String[] args) throws IOException {
String filePath = "e:\\a.txt";
//解读
//1. 把 FileInputStream 转成 InputStreamReader
//2. 指定编码 gbk
//InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath), "gbk");
//3. 把 InputStreamReader 传入 BufferedReader
//BufferedReader br = new BufferedReader(isr);
//将2 和 3 合在一起
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(filePath), "gbk"));
//4. 读取
String s = br.readLine();
System.out.println("读取内容=" + s);
//5. 关闭外层流
br.close();
}
}
对象流:提供了对基本类型或对象类型的序列化和反序列化的方法,关键字 Serializable
序列化(ObjectOutputStream):通俗来说就是将数据结构或对象转换成二进制串的过程
反序列化(ObjectInputStream): 也就是将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程
序列化:
package com.hspedu.outputstream_;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* @author 韩顺平
* @version 1.0
* 演示ObjectOutputStream的使用, 完成数据的序列化
*/
public class ObjectOutStream_ {
public static void main(String[] args) throws Exception {
//序列化后,保存的文件格式,不是存文本,而是按照他的格式来保存
String filePath = "e:\\data.dat";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
//序列化数据到 e:\data.dat
oos.writeInt(100);// int -> Integer (实现了 Serializable)
oos.writeBoolean(true);// boolean -> Boolean (实现了 Serializable)
oos.writeChar('a');// char -> Character (实现了 Serializable)
oos.writeDouble(9.5);// double -> Double (实现了 Serializable)
oos.writeUTF("韩顺平教育");//String
//保存一个dog对象
oos.writeObject(new Dog("旺财", 10, "日本", "白色"));
oos.close();
System.out.println("数据保存完毕(序列化形式)");
}
}
package com.hspedu.outputstream_;
import java.io.Serializable;
/**
* @author 韩顺平
* @version 1.0
*/
//如果需要序列化某个类的对象,实现 Serializable
public class Dog implements Serializable {
private String name;
private int age;
//序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员
private static String nation;
private transient String color;
//序列化对象时,要求里面属性的类型也需要实现序列化接口
private Master master = new Master();
//serialVersionUID 序列化的版本号,可以提高兼容性
private static final long serialVersionUID = 1L;
public Dog(String name, int age, String nation, String color) {
this.name = name;
this.age = age;
this.color = color;
this.nation = nation;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
", color='" + color + '\'' +
'}' + nation + " " +master;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
反序列化:
package com.hspedu.inputstream_;
import com.hspedu.outputstream_.Dog;
import java.io.*;
/**
* @author 韩顺平
* @version 1.0
*/
public class ObjectInputStream_ {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//指定反序列化的文件
String filePath = "e:\\data.dat";
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));
//读取
//老师解读
//1. 读取(反序列化)的顺序需要和你保存数据(序列化)的顺序一致
//2. 否则会出现异常
System.out.println(ois.readInt());
System.out.println(ois.readBoolean());
System.out.println(ois.readChar());
System.out.println(ois.readDouble());
System.out.println(ois.readUTF());
//dog 的编译类型是 Object , dog 的运行类型是 Dog
Object dog = ois.readObject();
System.out.println("运行类型=" + dog.getClass());
System.out.println("dog信息=" + dog);//底层 Object -> Dog
//这里是特别重要的细节:
//1. 如果我们希望调用Dog的方法, 需要向下转型
//2. 需要我们将Dog类的定义,放在到可以引用的位置
Dog dog2 = (Dog)dog;
System.out.println(dog2.getName()); //旺财..
//关闭流, 关闭外层流即可,底层会关闭 FileInputStream 流
ois.close();
}
}