IO流分类及详解

和我一起学习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流

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值