IO 流总结

一、介绍

IO -- I 表示 inputStream,O 表示 OutputStream,称为输入输出流;专门用来进行各类文件的读取和写出操作;根据读写文件的类型,IO 流分为字节流和字符流,根据输入输出的流向可分为输入和输出流; 其中还有缓冲流(辅助工具,提高节点流的工作效率,本身不具备读写文件的功能)、序列化流(用来实现对象的序列化与反序列化操作)、转换流(实现字节流到字符流的转换);

二、结构体系

727f0882c7bf4363aa848d2cab93ea5c.png

三、字节输入输出流

1、字节输入流 - InputStream

介绍

b85ed640e799481fbb8ee2ac227e9e89.png

主要方法

int available() -- 返回该输入流中可以读取的字节数

void close() -- 关闭流

abstract int read() -- 从输入流读取数据的下一个字节,没有读取到返回 -1,读取到就返回读到的字节数

int read(byte[] b) -- 从输入流读取一些字节数,并将它们存储到缓冲区 b

int read(byte[] b, int off, int len) -- 从输入流读取最多 len 字节的数据到一个字节数组

long skip(long n) -- 跳过字节数

FileInputStream

介绍

3dfe1d19233841e9be170141d7e0bb44.png

FileInputStream 是最主要的字节输入流子类,可用于任意文件的读取操作;

构造方法

09cd78bba2b04c7e975e07a0bd9d839e.png

主要方法

db0cc4876abf4ebb8d8317171da8c9a1.png

测试 -- 读取文件内容

public void test_file() throws IOException {
    FileInputStream f1 = new FileInputStream(new File("d://a/a.txt"));
    byte[] buf = new byte[1024]; // 使用数组可以提升读取效率
    int read;
    while((read = f1.read(buf)) != -1){
        System.out.println(Arrays.toString(buf));
    }
}

2、字节输出流 - OutputStream

介绍

OutputStream 字节输出流最顶层的父类,是一个抽象类,不能使用构造方法直接创建对象,需使用其子类 进行对象的创建,最常用的子类为 FileOutputStream,可用于一切数据(txt/mp3/mp4/png/doc/md) 的输出;

主要方法

36ee1ef6ad2e4abb8fe5ecbe54d4e1e6.png

FileOutputStream

介绍

4afdcd2f36c54c64a4145b9df8ac97e4.png

构造方法

a5d202e2953b4205accf39972d418939.png

核心方法

574b7648745c4215b837cbe0f984997a.png

案例

@Test
public void test_file() throws IOException {
    File file = new File("d://test");
    if(!file.exists()){
        file.mkdirs();
    }
    String string = "百度百科是百度公司推出的一部内容开放、自由的网络百科全书.";
    OutputStream fos = new FileOutputStream("d://test/test.txt");
    byte[] bytes = string.getBytes();
    fos.write(bytes);
    fos.close();
}

四、字符流输入输出流

介绍

① 字符流是以读写字符的方式进行文件操作,不管是中文、数字、还是字符,单个的存在都是一个字符,不会 像字节流一样进行汉字的拆分(字节流操作纯文本内容乱码的原因);

② 字符流内部自带缓冲空间,可以更快速的进行内容读写操作;但是读写的内容相对局限,只能操作纯文本内容;

1、字符输入流 - Reader

介绍

Reader 是字符输入流最顶层抽象类,内部定义了读取字符的核心方法,其最常用的子类为 FileReader

主要方法

13cecafe0bb34aab912ef0f40b484a0a.png

 FileReader

介绍

c0b5061bfbbb4b2f96e355e648690261.png

构造方法

fb641811eb2d4763a7173cc0a98ec6db.png

 主要方法

都继承于父类,自己没有定义新的方法;

案例

@Test
public void test_reader() throws IOException {
    FileReader fr = new FileReader("d://1.txt");
    char[] chars = new char[8];
    int read;
    while((read = fr.read(chars)) != -1){
        System.out.println(new String(chars,0,read));
    }
}

2、字符输出流 - Writer

介绍

字符输出流是以字符(字符串)的形式进行内容的输出,自带缓存,每一次的输出都需要进行流的冲刷,否则数据在缓存中进行保存,不会直接写到文件中;

冲刷的方式可以使用 flush 方法,也可以使用 close 方法;

主要方法

b58c2b52f3614c99a3bf23f8a07778b1.png

 FileWriter

介绍

d011838c2b9649e9a7e2de8eac7af428.png

构造方法 

1a7984dc6ca74b21b4303d42119e3bd6.png

 案例

db676cf282ca429f95052127cc408668.png

五、转换流

介绍

转换流用于字节流到字符流的转换;没有字符流到字节流的转换;在转换的同时可以实现编码格式的设置;因 此转换流用来进行目标文件和编码环境编码格式不统一时进行编码格式的同意设置;

转换流的创建实际就是字符流的创建,比普通的字符流创建多了一个设置编码格式的选择;

1、输入转换流 -- InputStreamReader 

介绍

fa72401b547f4bba83f69f8afed05412.png

构造方法

c301a346400145adbd7e9057a9fe248e.png

主要方法 

2242d7c49d4f42f0a0c819671ed3d643.png

案例 

b31bdbcdd7dd4fe498dac11023124c6c.png

2、输出转换流 -- OutputStreamWriter

介绍

6945c6fcaa1e41d5be9dfcc738b54a70.png

构造方法

7468d3d86e4f497fb3902597bb718acc.png

主要方法 

70d44b8f4f0244c8a46af7f4c70f0436.png

案例 

bda8b58100ae45518a56ef16451fc205.png

六、缓冲流

介绍

缓冲流不能直接操作文件,需要配合辅助节点流(字节流或字符流)进行文件操作;

缓冲流字节流内部创建了 8192 字节或字符的空间,用来进行读写数据的临时储存,类似于使用字节流使用数 组的方式实现读写数据,这样可以大大的提升读写的效率;

因此,缓冲流的作用就是提升字节流或字符流读写的能力;

1、缓冲字节流

输入流 -- BufferedInputStream 

构造方法

27f19d462cac4ed292375160d409100d.png

案例 

@Test
public void test_buffered() throws IOException {
    // 构建缓冲流
    BufferedInputStream bis = new BufferedInputStream(newFileInputStream("d://1.txt"));
    int read;
    while((read = bis.read()) != -1){}
    bis.close();
}
注意:缓冲流在使用时,比普通字节流和字符流的效率要高,但是不如使用小数组的字节流或字符流;
在缓冲流中也能自定义数组来进行数据的缓存,但是不建议如此操作,使用缓冲流尽量使用其自带的缓冲区;

输出流 -- BufferedOutputStream 

构造方法 

f85070d9f61c42b49a0fc1e8030a72e4.png

 案例

public void test_buffered() throws IOException {
    // 构建缓冲流
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d://1.txt"));
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d://2.txt"));
    int read;
    while((read = bis.read()) != -1){
        bos.write(read);
    }
    bos.close();
    bis.close();
}
注意:BufferedOutputStream 也自带了 8192 字节的缓冲空间;能够提升写出的效率;

2、缓冲字符流

输入流 -- BufferedReader

构造方法

e304736c6013470b93de5d9783cf3e49.png

案例 

@Test
public void test_buffered2() throws IOException{
    BufferedReader br = new BufferedReader(new FileReader("d://1.txt"));
    String read;
    while((read = br.readLine()) != null){}
    br.close();
}
注意:readLine 是字符输入流特有的方法,可以一次读取一行的字符串,返回值为读取到的字符串;可以进
一步提升读取数据的效率;

输出流 -- BufferedWriter

构造方法 

9ff7e4f25d784f05b16638f74c871ff8.png

案例 

public void test_buffered3() throws IOException{
    BufferedWriter br = new BufferedWriter(new FileWriter("d://2.txt"));
    br.write("静夜诗");
    br.newLine();
    br.write("床前明月光,");
    br.newLine();
    br.write("疑是地上霜。");
    br.newLine();
    br.write("举头望明月,");
    br.newLine();
    br.write("低头思故乡。");
    br.close();
}
注意:newLine()方法可以实现在任意操作系统上的换行功能;比起使用字符换行的操作更加通用,因为不同
操作系统的换行符是不一样的;

七、序列化流

介绍 

序列化表示将 java 对象通过字节流写出到指定的文件中的过程,以便于 Java 对象进行持久化保存和传 输;由于 java 语言的特点,对象只能在虚拟机运行期间存在,一旦虚拟机关闭,对象就消失;对象中储存的 数据也会消失,想要在虚拟机关闭后仍然保存对象信息,序列化对象是当前比较常用的一种手段;

跟序列化对应的操作为反序列化,反序列化是在序列化对象文件在传输过程中,读取文件中对象信息的一种手段;

序列化和反序列化都是以字节的形式进行数据的读写,因此归根到底即是字节输入流和输出流的使用;

对应的字节输出流 -- 序列化流(ObjectOutputStream)

对应的字节输入流 -- 反序列化流(ObjectInputStream)

一个类的对象想能被序列化,那么这个类需要实现序列化接口 -- Serializable

1、序列化 - ObjectOutputStream

介绍

e3fc429144f243efa8b0b970b8611b86.png

 构造方法

cb82ee15d2324ead9fc58194d9048545.png

主要方法 

2aa53a72f5074bcc8885791dc3cd2acd.png 案例

@Test
public void test_serializable() throws IOException {
    ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream("d://user.txt"));
    oos.writeObject(new User("小红",18));
    oos.close();
}

注意:序列化是使用 ObjectOutputStream 的 writeObject 方法将对象以字节的方式输出到指定文件中;文件中保存的内容是该对象的属性和值,以及序列化的版本号(如果类中没有手动定义,系统会自动生成一个);类的静态内容不能被序列化; 

 2、反序列化 - ObjectInputStream

介绍

c038c29dc3e044abb44fed5fc830ea72.png

构造方法 

509f67023b5a41a5a258200b41684664.png

核心方法

e447654c8d8d4163a7d460931e67d8d0.png

案例 

@Test
public void test_serializable2() throws IOException, ClassNotFoundException {
    FileInputStream fileInputStream = new FileInputStream("d://user.txt");
    ObjectInputStream ois = new ObjectInputStream(fileInputStream);
    Object o = ois.readObject();
    System.out.println(o);
}

注意:反序列时,jvm 虚拟机中必须要存在反序列化对象类型,而且类必须序列化之前具有相同的 serialVersionUID 否则反序列化会失败,并且抛出 InvalidClassException 异常; InvalidClassException 异常出现的原因:序列化时用的类的 serialVersionUID 和反序列化时用的 类 serialVersionUID 值不一致;

InvalidClassException 异常处理:

① 不要修改类的任何内容,serialVersionUID 是类中的内容进行生成的。

② 手动进行 serialVersionUID 声明,且声明为静态常量; 

 transient 关键字

transient 模糊序列化属性,被 transient 修饰的属性在进行序列化时,值不会序列化到文件中; 

八、Properties 类

介绍

Properties 是 java 中用于配置文件读取的类,在 java 编程中,很多地方需要有配置文件的支持,配 置文件有多种类型,例如,以 .properties、.xml、.txt 等结尾的文件;想要获取配置文件配置的信息, 就需要进行文件的读取,Properties 是可以进行多种不同类配置文件读取的类;

Properties 内部有大量读/写配置文件的方法,都是根据 IO 流来进行的文件读/写取操作; Properties 还是 Hahtable 的子类,属于双列集合的范畴,通过键值对的方式进行数据的储存,并且要求 健和值都是String 类型;除了有 map 集合通用的添加数据的方式以外,自己还定义专属的数据添加方法;

构造方法 

1f0dde4a307c45538b1d254281e855e2.png

 主要方法

操作内部元素的方法

ed9c85825a064339a4b4ed7f6e6057eb.png

读取配置文件的方法 

430d5377f7a14473a12fd1588b8ab224.png

写出数据到文件中 

b800dcf1de0a4c97958a9ef5606087b8.png

案例

@Test
public void test_properties1(){
    Properties properties = new Properties();
    properties.setProperty("1","2");
    properties.getProperty("1","3");
    Set<String> strings = properties.stringPropertyNames();
}
@Test
public void test_properties2() throws IOException {
    Properties properties = new Properties();
    properties.loadFromXML(new FileInputStream("d://jdbc.xml"));
    System.out.println(properties.getProperty("user"));
}
@Test
public void test_store() throws IOException{
    Properties properties = new Properties();
    properties.setProperty("driverClass","com.mysql.cj.jdbc.Driver");
    properties.setProperty("jdbcUrl","jdbc:mysql:///test1");
    properties.setProperty("user","root");
    properties.setProperty("password","root");
    properties.store(new FileOutputStream("d://jdbc.properties"),"mysql数据库的连接信息");
}
@Test
public void test_list(){
    Properties properties = new Properties();
    properties.setProperty("driverClass","com.mysql.cj.jdbc.Driver");
    properties.setProperty("jdbcUrl","jdbc:mysql:///test1");
    properties.setProperty("user","root");
    properties.setProperty("password","root");
    properties.list(System.out);
}

最后补充

IO 和 NIO 的区别:

这个NIO是 JDK1.7 以后有的,它们俩的主要区别是:io 是面向流,是阻塞 io,nio是面向缓冲,非阻塞的io; io 的话每次流中取一 或多个字节 ,直到读取完所有的字节 ,没有缓存到任何地方。nio 读取的是数据是有缓存,就是说他读取的数据是在缓冲里读的。另外的话,java中的各种 io 是阻塞的。就是说一个线程调用 read 或者 write() 时,这个线程就已经被阻塞了,直到读取到一些数据为止,或者是完全写入。在这个过程中不能干其他的事情。nio 的非阻塞模式,当发送一个读取数据的请求的时候,如果没有读取到可用的数据,就什么也不会获取,且不会让线程阻塞,写也是这样。非阻塞的 IO 的空闲时间可用来做其他的操作所以,一个单独的非阻塞线程可以管理多个输 入和输 出通道,另 外 NIO 还有一个 selector(选择器 ),它是可以管理多个输入输出的通道。

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值