简介
IO 即 Input/Output
,输入和输出,是存储和读取数据的解决方案。输入:数据输入到计算机内存的过程,输出:计算机内存输出到外部存储(比如数据库,文件,远程主机)的过程。数据传输过程类似于水流,因此称为 IO 流。IO 流在 Java 中分为输入流和输出流,而根据数据的处理方式又分为字节流和字符流。
Java l0 流的 40 多个类都是从如下4个抽象类基类中派生出来的
- Inputstream /Reader:所有的输入流的基类,前者是字节输入流,后者是字符输入流。
- OutputStream/writer:所有输出流的基类,前者是字节输出流,后者是字符输出流。
主要分类
1.按数据流向
-
输入流(InputStream/Reader):从外部读取数据到程序中。
-
输出流(OutputStream/Writer):从程序写出数据到外部。
2.按数据类型
-
字节流(InputStream/OutputStream):以字节为单位(8位),处理二进制数据。
- 字符流(Reader/Writer):以字符为单位(16位),处理文本数据。
3.按功能
-
节点流:直接从数据源/目的地读写数据。
-
处理流(包装流):对其他流进行包装,提供额外功能。
字节流
1.InputStream(字节输入流)(抽象类)
InputStream
用于从源头(通常是文件)读取数据(字节信息)到内存中,java.io.InputStream
抽象类是所有字节输入流的父类。
常用实现类:
-
FileOutputStream
:文件输出流 -
ByteArrayOutputStream
:字节数组输出流 -
BufferedOutputStream
:缓冲输出流(处理流) -
ObjectOutputStream
:对象序列化流(处理流) -
PrintStream
:打印流(处理流)
常用方法:
int read() // 读取一个字节
int read(byte[] b) // 读取多个字节到数组
int read(byte[] b, int off, int len) // 读取len个字节到数组指定位置
void close() // 关闭流
FileOutputStream实例
import java.io.FileInputStream;
import java.io.IOException;
public class test {
public static void main(String[] args) throws IOException {
FileInputStream fos = new FileInputStream("E:\\作业文档集\\框架设计与技术\\22 配套资源\\Test\\IO\\src\\main\\resources\\a.txt");
//2.读取数据
int c;
while ((c = fos.read())!= -1) {
System.out.print((char) c);
}
//3.关闭流
fos.close();
}
}
运行结果是输出a.txt文件的英文和数字(文件里有中文会乱码)
2.OutputStream(字节输出流)(抽象类)
OutputStream
用于将数据(字节信息)写入到目的地(通常是文件),java.io.OutputStream
抽象类是所有字节输出流的父类。
常用实现类:
-
FileOutputStream
:文件输出流 -
ByteArrayOutputStream
:字节数组输出流 -
BufferedOutputStream
:缓冲输出流(处理流) -
ObjectOutputStream
:对象序列化流(处理流) -
PrintStream
:打印流(处理流)
常用方法:
void write(int b) // 写入一个字节
void write(byte[] b) // 写入字节数组
void write(byte[] b, int off, int len) // 写入字节数组的一部分
void flush() // 刷新缓冲区
void close() // 关闭流
FileOutputStream实例
import java.io.FileOutputStream;
import java.io.IOException;
public class test {
public static void main(String[] args) throws IOException {
//1.创建字节输入流对象
// 细节1:false表示覆盖模式(重复运行程序,会覆盖原文件,如txt文件内容一直是97),true表示续写模式(重复运行程序,会覆盖原文件,如txt文件内容是979797....)
// 细节2:如果文件不存在,则会自动创建(父类目录必须存在)
// 细节3:
FileOutputStream fos = new FileOutputStream("E:\\作业文档集\\框架设计与技术\\22 配套资源\\Test\\IO\\src\\main\\resources\\a.txt",false);
//2.写数据
fos.write(97);
//3.关闭流
fos.close();
}
}
程序的运行结果是向文件a.txt写入数据“a”
3.字符流
1. Reader(抽象类)
常用实现类:
-
FileReader
:文件字符输入流 -
InputStreamReader
:字节流转字符流(处理流) -
BufferedReader
:缓冲字符输入流(处理流)
常用方法:
int read() // 读取一个字符
int read(char[] cbuf) // 读取字符到数组
int read(char[] cbuf, int off, int len) // 读取len个字符到数组指定位置
void close() // 关闭流
2. Writer(抽象类)
常用实现类:
-
FileWriter
:文件字符输出流 -
OutputStreamWriter
:字符流转字节流(处理流) -
BufferedWriter
:缓冲字符输出流(处理流) -
PrintWriter
:打印字符输出流(处理流)
常用方法:
void write(int c) // 写入一个字符
void write(char[] cbuf) // 写入字符数组
void write(char[] cbuf, int off, int len) // 写入字符数组的一部分
void write(String str) // 写入字符串
void write(String str, int off, int len) // 写入字符串的一部分
void flush() // 刷新缓冲区
void close() // 关闭流
4.转换流(是字节流和字符流直接的桥梁)
转换流的作用:
- 利用转化流可以按照指定的字符编码读取、写入。
- 字节流想要使用字符流中的方法了。
- InputStreamReader(转换输入流)
- OutputStreamWriter(转化输出流)
1.字节流想要使用字符缓冲流BufferedReader中的readLine方法了
import java.io.*;
public class test3 {
public static void main(String[] args) throws IOException {
// 利用字节流读取文件中的数据,每次读一整行,而且不能出现乱码
BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("E:\\作业文档集\\框架设计与技术\\22 配套资源\\Test\\IO\\src\\main\\resources\\c.txt")));
String line;
while ((line=br.readLine())!=null){
System.out.println(line);
}
br.close();
}
}
2.利用转化流可以按照指定的字符编码读取、写入
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.Charset;
public class test2 {
public static void main(String[] args) throws IOException {
// 读入GBK编码的文本文件,输出UTF-8编码的文本文件
FileReader fr = new FileReader("C:\\桌面\\新建文本文档.txt", Charset.forName("GBK"));
FileWriter fw = new FileWriter("E:\\作业文档集\\框架设计与技术\\22 配套资源\\Test\\IO\\src\\main\\resources\\b.txt", Charset.forName("UTF-8"));
int c;
while((c= fr.read())!= -1){
fw.write(c);
}
fw.close();
fr.close();
}
}
5.序列化流/反序列化流
1.序列化流
将Java中的对象写入本地文件中
代码实例
import java.io.*;
public class test4 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//创建序列化流的对象/对象操作输出流
ObjectOutputStream ois=new ObjectOutputStream(new FileOutputStream("E:\\作业文档集\\框架设计与技术\\22 配套资源\\Test\\IO\\src\\main\\resources\\d.txt"));
//创建对象
Student s=new Student("附件阿卡丽",12);
//序列化对象
ois.writeObject(s);
//关闭流
ois.close();
}
}
序列化结果:
细节:
- Javabean类需要实现Serializable接口,表示这个Javabean类可以被序列化,否则会报NotSerializableException异常。
- 在序列化对象时,会向文件中存储对象的版本号,当我们向Javabean中添加属性重新序列化时,版本号会和文件已经存储的版本号冲突,所以Javabean类需指定版本号,使得版本号不变。如下:
2.反序列化流
可以把序列化到本地文件中的对象,读取到程序中来
代码实例
import java.io.*;
public class test4 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois3=new ObjectInputStream(new FileInputStream("E:\\作业文档集\\框架设计与技术\\22 配套资源\\Test\\IO\\src\\main\\resources\\d.txt"));
Object ob=ois3.readObject();
System.out.println(ob);
ois3.close();
}
}
6.打印流
分类:PrintStream(字节打印流)、PrintWriter(字符打印流)
特点:
- 打印流质操作文件目的地,不操作数据源。(只写不读)
- 特有的写入方法可以实现,数据原样写入。
- 特有的写出方法,可以实现自动刷新,自动换行。
1.字节打印流
2.字符打印流
7.压缩流/解压缩流
1.解压缩流
解压本质:把每一个ZipEntry按照层级拷贝到本地另一个文件夹中
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class test {
public static void main(String[] args) throws IOException {
//1.创建一个File表示要解压的压缩包
File src = new File( "D:\\aaa.zip");
//2.创建一个File表示解压的目的地
File dest = new File( "D:\\");
//调用方法
unzip(src,dest);
}
private static void unzip(File src, File dest) throws IOException {
//创建一个解压缩流用来读取压缩包中的数据
ZipInputStream zip = new ZipInputStream(new FileInputStream(src));
//要先获取到压缩包里面的每一个zipentry对象
// 表示当前在压缩包中获取到的文件或者文件夹
ZipEntry entry;
while((entry = zip.getNextEntry())!= null) {
System.out.println(entry);
if (entry.isDirectory()) {
//文件夹:需要在目的地dest处创建个同样的文件夹
File file = new File(dest, entry.toString());
file.mkdirs();
} else {
//文件:需要读取到压缩包中的文件,并把他存放到目的地dest文件夹中(按照层级目录进行存放)
FileOutputStream fos = new FileOutputStream(new File(dest, entry.toString()));
int b;
while ((b = zip.read()) != -1) {
//写到目的地
fos.write(b);
}
fos.close();
//表示在压缩包中的一个文件处理完毕了
zip.closeEntry();
}
}
}
}
2.压缩流
压缩本质:把每一个(文件/文件夹)看成ZipEntry对象放到压缩包中
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class test {
public static void main(String[] args) throws IOException {
//1.创建一个File表示要解压的压缩包
File src = new File( "D:\\aaa.zip");
//2.创建一个File表示解压的目的地
File dest = new File( "D:\\");
//调用方法
toZip(src,dest);
}
private static void toZip(File src, File dest) throws IOException {
//1.创建一个ZipInputStream对象,读取压缩包
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(dest,"a.zip")));
//2.创建一个ZipEntry对象,并设置压缩文件名
ZipEntry entry = new ZipEntry("a.txt");
//3.将压缩文件写入到ZipOutputStream中
zos.putNextEntry(entry);
zos.closeEntry();
zos.close();
}
}