和我一起学习Java吧,加油!
文章目录
前言
流是一种抽象概念,它代表了数据的无结构化传递。按照流的方式进行输入输出,数据被当成无结构的字节序或字符序列。从流中取得数据的操作称为提取操作,而向流中添加数据的操作称为插入操作。用来进行输入输出操作的流就称为IO流。换句话说,IO流就是以流的方式进行输入输出。
一、File
File 文件路径的抽象表现形式
注意 : java中字符串中定义路径 的分隔符可以为 / // \\
\ 不能使用,会识别为转义字符
常用功能可查询
二、IO流
需求 : 读写文件内部的内容,File类无法实现,没有提供这样功能,所以可以通过IO实现
IO流 :
流 : 指一连串流动的数据,以先入先出的方式发送数据,流就是管道
数据源 ---> 数据 ---> 目的地
流的分类 :
按照流向分 : (以程序(人大脑)为中心)
输入流
输出流
操作单元分 :
字节流 : 万能流
字符流 : 只能传输纯文本文件
按照功能分 :
节点流 : 从数据源到目的地直接传输,真实做读入写出能力
功能流(包装流) : 从数据源经过包装再到目的地--> 增强节点流的功能,提高节点流的性能
注意 : 不同层面的流存在不同的划分,但是不冲突,都是相辅相成的
java.io 包下提供使用io相关的类型
1.Inputstream
InputStream : 此抽象类是表示输入字节流的所有类的超类。
操作不同的数据源,字节输入流提供了不同的子类
文件流
FileInputStream 文件字节输入流
字节数组(了解)
ByteArrayInputStream 字节输入数组流
文件字节输入流使用步骤 :
1.与文件建立联系(表示文件)
2.构建输入流
3.读入数据
4.处理数据
5.关闭
代码
// 1.与文件建立联系(表示文件)
// 2.构建输入流
InputStream is = new FileInputStream("D://test.txt");
// 3.读入数据
//int read() 从此输入流中读取一个字节的数据。
int num = -1;
while((num=is.read())!=-1){
// 4.处理数据
System.out.println((char)num);
}
// 5.关闭
is.close();
优化
/*
文件字节输入流使用 :
每次读取一个字节数据,重复读取多次,效率太低--->每次读取一卡车数据,重复读取多次
int read(byte[] b) 从此输入流 b.length最多 b.length字节的数据读 b.length字节数组。
返回值 : 读入缓冲区的总字节数,如果由于文件末尾已到达而没有更多数据, -1 。
*/
//1.构建流
InputStream is = new FileInputStream("D://test.txt");
//2.读取
int len = -1;
byte[] car = new byte[1024];
while((len = is.read(car))!=-1){
//3.处理
System.out.println(new String(car,0,len));
}
//4.关闭
is.close();
再优化
//构建流
InputStream is = new FileInputStream("D://test.txt");
//byte[] readAllBytes() 从输入流中读取所有剩余字节。
byte[] datas = is.readAllBytes();
System.out.println(new String(datas));
//4.关闭
is.close();
2.OutputStream
字节输出流 OutputStream : 此抽象类是表示输出字节流的所有类的超类。
节点流 输出流 节点流
根据目的地选择使用哪一种具体的字节输出流的子类
文件字节输出流 FileOutputStream
字节数组输出流(了解) ByteArrayOutputStream
文件字节输出流使用步骤 :
1.构建File对象目的地
2.构建输出流
3.准备数据
4.写出
5.刷出
6.关闭
注意 :
在使用输出流的时候,如果目的地文件不存在,系统会自动创建目的地文件,但是如果目的地文件所在路径不存在,不会创建,会抛出异常java.io.FileNotFoundException
向文件中写出内容时候,会默认覆盖原文件内容,如果想要实现追加,在构建流的构造器中可以添加一个参数boolean append->true追加,默认false不追加覆盖
代码
//1.构建File对象目的地
//2.构建输出流
//OutputStream os = new FileOutputStream(dest);
OutputStream os = new FileOutputStream("D://hehe.txt",true);
//3.准备数据
int num = 97;
byte[] arr = "你好".getBytes();
//4.写出
//void write(byte[] b) 将指定字节数组中的 b.length字节写入此文件输出流。
//void write(byte[] b, int off, int len) 将从偏移量 off开始的指定字节数组中的 len字节写入此文件输出流。
//void write(int b) 将指定的字节写入此文件输出流。
os.write(num);
os.write(arr);
//5.刷出
os.flush();
//6.关闭
os.close();
3.字节流拷贝文件
拷贝文件 : *****
数据源文件—> 输入流—> 程序 —>输出流—> 目的地文件
步骤 :
1.构建流
输入流
输出流
2.读写数据
3.刷出
4.关闭(后打开的先关闭)
代码
异常抛出
// 1.构建流
InputStream is = new FileInputStream("D://test.txt");
OutputStream os = new FileOutputStream("D://AAA/test.txt",true);
// 2.读写数据
int len = -1; //记录每次读入到字节数组中数据的个数
byte[] car = new byte[1024];
while((len = is.read(car))!=-1){
os.write(car,0,len); //写出字节数组中读入的数据
}
// 3.刷出
os.flush();
// 4.关闭(后打开的先关闭)
os.close();
is.close();
异常捕获
// 1.构建流
InputStream is = null;
OutputStream os = null;
try {
is = new FileInputStream("D://test.txt");
os = new FileOutputStream("D://AAA/haha.txt",true);
// 2.读写数据
int len = -1; //记录每次读入到字节数组中数据的个数
byte[] car = new byte[1024];
while((len = is.read(car))!=-1){
os.write(car,0,len); //写出字节数组中读入的数据
}
// 3.刷出
os.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4.关闭(后打开的先关闭)
if(os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
封装CopyFile类
public static void copyFile(String src, String dest) throws FileNotFoundException {
copyFile(src!=null?new File(src):null,dest!=null?new File(dest):null);
}
public static void copyFile(File src, File dest) throws FileNotFoundException {
//判断是否存在src,dest对象
if(src==null || dest==null){
throw new NullPointerException("数据源或目的地为null!!!");
}
//判断数据源文件在系统中是否真实存在,存在才能拷贝,不存在不能拷贝
if(!src.exists()){
throw new FileNotFoundException("数据源在系统中不存在...");
}
/**
*异常捕获代码
*/
}
4.Reader|Writer
字符流 : (只能操作纯文本)
Reader 用于读取字符流的抽象类。
文件字符输入流FileReader : 节点流 输入流 字符流
无新增功能,可以发生多态:
Reader reader = new FileReader(path);
Writer 用于写入字符流的抽象类。
文件字符输出流FileWriter : 节点流 输出流 字符流
无新增功能,可以发生多态:
Writer writer = new FileWriter(path);
注意 :
方法的调用 : 执行方法中的代码
方式 : 方法名(参数列表)
5.Buffered缓冲流
缓冲流 : 加快读写效率
功能流 (节点流)
字节缓冲流
字节输入缓冲流 BufferedInputStream
无新增方法,可以发生多态:
InputStream input = new FileInputStream(path);
字节输出缓冲流 BufferedOutputStream
无新增方法,可以发生多态
OutputStream output = new FileOutputStream(path);
字符缓冲流
字符输入缓冲流 BufferedReader
新增方法 : String readLine() 读一行文字。
字符输出缓冲流 BufferedWriter
新增方法 : void newLine() 写一个行分隔符。
6.Data流
Data流 | 基本数据类型流 : 传输数据+保留数据类型(基本数据类型+String)
功能流–>字节流的功能流
//Xxx为基本数据类型或String
Data输入流 : DataInputStream
新增方法 : readXxx()
Data输出流 : DataOutputStream
新增方法 : writeXxx(Xxx args)
注意 :
读入的顺序与写出的顺序要求保持一致
读入的是写出的源文件
7.Object流
Object流 | 对象流 | 引用数据类型流 : 数据+类型(基本|引用) *****
字节流的功能流
当读写,传输对象数据,可以选择Object流,能够读写数据的同时保留数据的类型
序列化输出流 : ObjectOutputStream
新增方法 : writeXxx(Xxx args)
void writeObject(Object obj) 将指定的对象写入ObjectOutputStream。
反序列化输入流 : ObjectInputStream
新增方法 : Xxx readXxx()
Object readObject() 从ObjectInputStream中读取一个对象。
序列化 : 将对象转化为可存储或者可传输的状态的过程
反序列化:将可存储或者可传输的状态的数据转化为对象的过程
注意:
引用数据类型数据为对象数据
先序列化后反序列化
不是所有的类型的对象都能序列化 实现Serializable接口
反序列化与序列化顺序一致
transient修饰的数据不会序列化
static属性不会序列化
如果父类实现序列化接口,子类没有实现序列化接口,可以序列化所有内容
如果子类实现序列化接口,但是父类没有实现,只能序列化子类的属性
代码详注
//Student必须实现接口Serializable类才能序列化
class Student implements Serializable {
//设置该值后,序列号固定,类中属性、功能更新,不影响使用
private static final long serialVersionUID = 5064050517577213669L;
private int id;
private transient String name; //transient修饰的数据不会序列化
static int testStatic = 100; //静态属性不会序列化
public Student() {
}
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;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
"testStatic = "+testStatic+
'}';
}
}
总结
本章先讲解了输入流和输出流,之后又讲解了字符流和功能流,重点要学会字节流和object流