当前位置: 首页 > news >正文

JavaSE之深入浅出 IO 流:字节流、字符流与序列化流详解(含完整代码示例)

JavaSE之深入浅出 IO 流:字节流、字符流与序列化流详解(含完整代码示例)

一、字节流

1、IO流介绍以及输入输出以及流向的介绍

1.I:Input  输入O:Output 输出2.概述:从专业的角度去说:从一个设备上将数据传输到另外一个设备上的技术 -> IO流技术3.从专业角度上来说IO流流向怎么区分:相对的谁发送数据,谁就是输出谁接手数据,谁就是输入

2、IO流的流向_针对se阶段的IO

se部分的IO流流向区分,先找参照物->内存1.输出:将内存中的数据写到硬盘上保存
2.输入:将硬盘上的数据读会回到内存中来

3、IO流分类

1.字节流(万物皆字节,字节流是一个万能流(侧重的是文件复制))OutputStream:字节输出流的父类 -> 抽象类InputStream:字节输入流的父类 -> 抽象类2.字符流(专门操作文本文档的)Writer: 字符输出流的父类 -> 抽象类Reader: 字符输入流的父类 -> 抽象类

IO流四大基类: > > OutputStream > > InputStream > > Writer > > Reader

4、OutputStream中子类[FileOutputStream]的介绍以及方法的简单介绍

1.字节输出流概述:FileOutputStream是OutputStream的子类
2.作用:将数据写到文件中(保存到文件中)
3.构造:FileOutputStream(String path)FileOutputStream(File file)  
4.方法:a.write(int i) -> 一次写一个字节b.write(byte[] bytes) -> 一次写一个字节数组c.write(byte[] bytes,int offset,int length)-> 一次写一个字节数组的一部分bytes:要写的数组offset:从数组的哪个索引开始写length:写多少个d.close():关流5.细节:a.如果指定的文件没有,FileOutputStream会自动创建b.默认情况下,每运行一次,都会重新创建一个新的文件,覆盖老文件  
 package com.code.day20;import java.io.FileOutputStream;
import java.io.IOException;public class Demo01FileOutputStream {public static void main(String[] args) throws IOException {method1();method2();method3();method4();}/*** 一次写一个字节* @throws IOException*/public static void method1() throws IOException {FileOutputStream fileOutputStream = new FileOutputStream("D:\\java-code\\java-full-stack\\01-java-base\\src\\com\\code\\day20\\file\\demo1.txt");fileOutputStream.write(97);fileOutputStream.close();}/*** 一次写一个字节组* @throws IOException*/public static void method2() throws IOException {FileOutputStream fileOutputStream = new FileOutputStream("D:\\java-code\\java-full-stack\\01-java-base\\src\\com\\code\\day20\\file\\demo1.txt");byte[] bytes = {97,98,99,100};fileOutputStream.write(bytes);fileOutputStream.close();}/*** 一次写一个字节数组的一部分* @throws IOException*/public static void method3() throws IOException {FileOutputStream fileOutputStream = new FileOutputStream("D:\\java-code\\java-full-stack\\01-java-base\\src\\com\\code\\day20\\file\\demo1.txt");byte[] bytes = {97,98,99,100};fileOutputStream.write(bytes,1,3);fileOutputStream.close();}/*** 一次写一个字节的汉字* @throws IOException*/public static void method4() throws IOException {FileOutputStream fileOutputStream = new FileOutputStream("D:\\java-code\\java-full-stack\\01-java-base\\src\\com\\code\\day20\\file\\demo1.txt");fileOutputStream.write("你好".getBytes());fileOutputStream.close();}}

续写追加以及换行

1.续写追加:FileOutputStream(String path,boolean append)
如果append为true,就是续写追加,就不会每次都产生一个新的文件覆盖老文件了
2.换行:需要将换行符写到文件中
windows: \r\n
linux: \n
mac os : \

package com.code.day20;import java.io.FileOutputStream;
import java.io.IOException;public class Demo02FileOutputStream {public static void main(String[] args) throws IOException {method1();}public static void method1() throws IOException {FileOutputStream fileOutputStream = new FileOutputStream("D:\\java-code\\java-full-stack\\01-java-base\\src\\com\\code\\day20\\file\\demo2.txt", true);fileOutputStream.write("床前明月光\r\n".getBytes());fileOutputStream.write("疑是地上霜\r\n".getBytes());fileOutputStream.write("举头望明月\n".getBytes());fileOutputStream.write("低头思故乡\n".getBytes());fileOutputStream.close();}}

5、InputStream子类[FileInputStream]的介绍以及方法的使用

1.概述:FileInputStream   继承于InputStream
2.作用:将数据从文件中读到内存中
3.构造:FileInputStream(String path)FileInputStream(File file)
4.方法:a.int read() 一次读一个字节,返回的是读取到的字节b.int read(byte[] bytes) 一次读一个字节数组,返回的是读取的个数(数组定多长,每次读多少个)c.int read(byte[] bytes,int offset,int length) 一次读取一个字节数组一部分,返回的是读取个数d.close() 关流 部分堆对象无法被GC垃圾回收器回收 因此要手动关闭
5.细节:a.如果指定的文件没有,FileOutputStream会自动创建b.默认情况下,每运行一次,都会重新创建一个新的文件,覆盖老文件    	c.如果为读对象不会创建	

6、一次读取一个字节


public class Demo03FileInputStream {public static void main(String[] args) throws IOException {method();}public static void method() throws IOException {FileInputStream fileInputStream = new FileInputStream("D:\\java-code\\java-full-stack\\01-java-base\\src\\com\\code\\day20\\file\\demo1.txt");int len = 0;while ((len = fileInputStream.read()) != -1)System.out.println((char) len);}
}

1.用一个流对象读取完之后,再读啥也读不出来的;如果还想读,重新new对象

2.流关闭之后,不能再用了 否则会报错

java > Exception in thread "main" java.io.IOException: Stream Closed > at java.base/java.io.FileInputStream.read0(Native Method) > at java.base/java.io.FileInputStream.read(FileInputStream.java:228) > at com.atguigu.b_input.Demo01FileInputStream.method01(Demo01FileInputStream.java:39) > at com.atguigu.b_input.Demo01FileInputStream.main(Demo01FileInputStream.java:8) > 

7、读取-1的问题

每个文件中的末尾都有一个结束标记,如果读到结束比较之后,会直接返回-1

8、一次读取一个字节数组以及过程

public class Demo04FileInputStream {public static void main(String[] args) throws IOException {/*** int read(byte[] b) 一次读多个字节,返回的是读取到的字节个数*/FileInputStream fileInputStream = new FileInputStream("D:\\java-code\\java-full-stack\\01-java-base\\src\\com\\code\\day20\\file\\demo1.txt");byte[] bytes = new byte[3];int len = 0; //接收的字节个数while ((len = fileInputStream.read(bytes)) != -1) {System.out.println(new String(bytes, 0, len));
//            System.out.println(new String(bytes)); // 如果直接转为字符串 则可能会导致有一个数据被覆盖 而另一个没被覆盖}}
}

数组的长度一般定义长度为1024或者其倍数

不能直接使用一下方法

while ( fileInputStream.read(bytes)!= -1) { //读取第一个
System.out.println(fileInputStream.read(bytes)); //读取第二个 并输出第二个

​ }

以上方法会导致读取到的第一个字节未被输出

9、字节流实现图片复制分析

不能够边写边读

10、字节流实现图片复制代码实现

package com.code.day20;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;public class Demo05Copy {public static void main(String[] args) throws IOException {FileInputStream fileInputStream = new FileInputStream("D:\\java-code\\java-full-stack\\01-java-base\\src\\com\\code\\day20\\img\\1726621487689.png");FileOutputStream fileOutputStream = new FileOutputStream("D:\\java-code\\java-full-stack\\01-java-base\\src\\com\\code\\day20\\刘大胆.jpg"); //需要指定文件复制后的名称byte[] bytes = new byte[1024];int len = 0; while ((len = fileInputStream.read(bytes)) != -1) { //先读后写fileOutputStream.write(bytes, 0, len);}//先开的流 后关fileOutputStream.close();fileInputStream.close();}
}

二、字符流

1、字节流读取中文的问题

1.编码:将数据按照指定的规则保存的过程,叫做编码
2.解码:将数据按照指定的规则读取出来的过程,叫做解码3.GBK: 一个汉字占2个字节UTF-8: 一个汉字占3个字节4.注意:a.字节流称之为万能流(特指文件复制),我不管到底是什么编码规范,最终只要总字节数没有丢,文件复制过去就会正常显示,但是不要边读边看,如果边读边看的话,即使编码和解码规则一样,也有可能导致看到的是乱码b.解决:我们在读取文本文档的时候,如果把内容看成是一个一个的字符去操作,就可以了    

> 说明:即使用字符流去操作文本文档,那么前提也是编码和解码规则一致 > > 如果编码解码规则不一致,字符流操作也会出现乱码情况

> 字符流操作文本文档,如果编码和解码一致,边读边看是不会乱的 > > 字节流操作文本文档,即使编码和解码一致,边读边看也有可能出现乱码

2、FileReader的介绍以及使用

1.概述:FileReader extends Reader
2.作用:读数据
3.构造:FileReader(String path)FileReader(File file)   
4.方法:int read() 一次读一个字符,返回的是读取的字符int read(char[] chars) 一次读一个字符数组,返回的是读取个数int read(char[] chars,int offset,int length) 一次读取一个字符数组一部分,返回的是读取个数close() 关流    
package com.code.day20;import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;public class Demo06FileReader {public static void main(String[] args) throws IOException {
//        method();method1();}/*** int read() 一次读一个字符,返回的是读取的字符*/public  static  void method() throws IOException {FileReader fileReader = new FileReader("D:\\java-code\\java-full-stack\\01-java-base\\src\\com\\code\\day20\\file\\demo3.txt");int len =0;while((len = fileReader.read())!=-1){System.out.print((char)len);}fileReader.close();}/*** int read(char[] cbuf) 一次读多个字符,返回的是读取的字符个数*/public static  void method1() throws IOException {FileReader fileReader = new FileReader("D:\\java-code\\java-full-stack\\01-java-base\\src\\com\\code\\day20\\file\\demo3.txt");char[] chars = new char[1024];int len= 0;while((len=fileReader.read(chars))!=-1){System.out.print(new String(chars,0,len));}}
}

注意:如果要涉及到文件复制,不要使用字符流,要使用字节流

3、FileWriter的介绍以及使用

1.概述:FileWriter extends Writer
2.作用:写数据
3.构造:FileWriter(String path)FileWriter(File file)FileWriter(String path,boolean append)append为true就是追加续写    
4.方法:a.write(int i) 一次写一个字符b.write(char[] chars) 一次写一个字符数组c.write(char[] chars,int offset,int length) 一次写一个字符数组一部分d.write(String s) 一次写一个字符串e.close()f.flush() //刷新缓冲区   
5.注意:FileWriter底层有一个缓冲区,我们所写的数据,先进缓冲区,然后再从缓冲区中将数据刷到文件中
public class Demo07FileWriter {public static void main(String[] args) throws IOException {FileWriter fileWriter = new FileWriter("D:\\java-code\\java-full-stack\\01-java-base\\src\\com\\code\\day20\\file\\demo3.txt",true);fileWriter.write("我叫刘大胆\n");fileWriter.write("我叫超级无敌刘大胆\n");fileWriter.close();}
}

快速将一段代码抽取到方法中: > > 1.选中要抽取的代码 > > 2.ctrl+alt+m

4、FileWriter的刷新功能和关闭功能

1.flush:将数据从缓冲区中刷到文件中,但是流没关闭,后续还能使用这个流对象
2.close:先将数据刷到文件中,然后再关流,后续流对象无法使用

5、IO异常处理的方式

package com.code.day20;import java.io.FileWriter;
import java.io.IOException;public class Demo09IOEx {public static void main(String[] args) {FileWriter fileWriter = null;try {fileWriter = new FileWriter("D:\\java-code\\java-full-stack\\01-java-base\\src\\com\\code\\day20\\file\\demo4.txt");fileWriter.write("你好");} catch (IOException e) {e.printStackTrace();} finally {try {fileWriter.close();} catch (IOException e) {e.printStackTrace();}}}
}

6、JDK7之后io异常处理方式

1.格式:
try(IO对象;IO对象){可能出现异常的代码
}catch(异常 对象名){异常处理代码
}2.特点:自动关流
代码相对臃肿public class Demo10IOEX {public static void main(String[] args) {try( FileWriter fileWriter = new FileWriter("D:\\java-code\\java-full-stack\\01-java-base\\src\\com\\code\\day20\\file\\demo4.txt");) {fileWriter.write("你好你好");} catch (IOException e) {e.printStackTrace();}}
}

7、JDK9之后的IO异常处理方式(了解)

之前我们讲过JDK 1.7引入了trywith-resources的新特性,可以实现资源的自动关闭,此时要求:

  • 该资源必须实现java.io.Closeable接口

  • 在try子句中声明并初始化资源对象

  • 该资源对象必须是final的

    public class Demo11IOEX {public static void main(String[] args) throws IOException {FileWriter fileWriter = new FileWriter("D:\\java-code\\java-full-stack\\01-java-base\\src\\com\\code\\day20\\file\\demo4.txt");try (fileWriter) {fileWriter.write("你好你好你好");} catch (IOException e) {e.printStackTrace();}}
    }
    

JDK1.9又对trywith-resources的语法升级了

  • 该资源必须实现java.io.Closeable接口
  • 在try子句中声明并初始化资源对象,也可以直接使用已初始化的资源对象
  • 该资源对象必须是final的
IO流对象1声明和初始化;
IO流对象2声明和初始化;try(IO流对象1;IO流对象2){可能出现异常的代码
}catch(异常类型 对象名){异常处理方案
}
public class Demo05FileWriter {public static void main(String[] args)throws Exception {FileWriter fw = new FileWriter("day20_IO\\4.txt");/*可以减轻try的压力同时可以自动关流*/try(fw) {fw.write("床前明月光11111");} catch (Exception e) {e.printStackTrace();}}
}

三、序列化流

1、序列化流和反序列化流介绍

1.序列化流:写对象
2.反序列化流:读对象

2、序列化流_ObjectOutputStream

1.概述:ObjectOutputStream  extends OutputStream
2.作用:写对象
3.构造:ObjectOutputStream(OutputStream out) 
4.方法:writeObject(Object obj)5.注意:如果想让一个对象序列化到文件中,此时此对象需要实现序列化接口
package com.code.day20;import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;public class Demo12Serializable {public static void main(String[] args) throws IOException {method();}public  static  void method() throws IOException {ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\java-code\\java-full-stack\\01-java-base\\src\\com\\code\\day20\\file\\demo5.txt"));Person person = new Person("张三",18);objectOutputStream.writeObject(person);objectOutputStream.close();}}
package com.code.day20;import java.io.Serializable;public class Person implements Serializable {private String name;private Integer age;public Person() {}public Person(String name, Integer age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}
}

3、反序列化_ObjectInputStream

1.概述:ObjectInputStream extends InputStream
2.作用:读对象
3.构造:ObjectInputStream(InputStream in)
4.方法:Object readObject()
package com.code.day20;import java.io.*;public class Demo12Serializable {public static void main(String[] args) throws IOException, ClassNotFoundException {read();//反序列化流}public static void read() throws IOException, ClassNotFoundException {ObjectInputStream objectInputStream =new ObjectInputStream(new FileInputStream("D:\\java-code\\java-full-stack\\01-java-base\\src\\com\\code\\day20\\file\\demo5.txt"));Object o = objectInputStream.readObject();Person person = (Person) o;System.out.println(person);}}

4、不想被序列化操作(了解)

 在成员前面加上一个关键字:transient

5、反序列化时出现的问题以及分析以及解决

1.问题描述:我们修改了源码,但是没有重新序列化,直接反序列化了,就会出现序列号冲突问题
public class Person implements Serializable {static final long serialVersionUID = 42L; //固定序列号private String name;public Integer age;public Person() {}public Person(String name, Integer age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}
}

6、经验问题

1.如果循环反序列化循环次数不对了,很容易出现EOFException(文件意外到达结尾异常)
2.问题解决:将多个对象放到一个集合中,将这个集合序列化到文件中,将来直接反序列化一个集合,然后集合拿出来了,我们遍历的次数就确定了,就不会出现这个问题了  
package com.code.day20;import java.io.*;
import java.util.ArrayList;import static com.code.day20.Demo12Serializable.read;public class Demo13JingYan {public static void main(String[] args) throws IOException, ClassNotFoundException {
//        write(); //序列化read(); //反序列化}public static void write() throws IOException {ObjectOutputStream objectOutputStream =new ObjectOutputStream(new FileOutputStream("D:\\java-code\\java-full-stack\\01-java-base\\src\\com\\code\\day20\\file\\demo6.txt"));ArrayList<Person> list = new ArrayList<>();Person p1 = new Person("张三", 18);Person p2 = new Person("李四", 18);Person p3 = new Person("王五", 18);list.add(p1);list.add(p2);list.add(p3);objectOutputStream.writeObject(list);objectOutputStream.close();}public static void read() throws IOException, ClassNotFoundException {ObjectInputStream objectInputStream =new ObjectInputStream(new FileInputStream("D:\\java-code\\java-full-stack\\01-java-base\\src\\com\\code\\day20\\file\\demo6.txt"));Object o = objectInputStream.readObject();ArrayList<Person> list = (ArrayList<Person>) o;for (Person person : list) {System.out.println(person);}objectInputStream.close();}
}

文章转载自:

http://BcuZZVN0.qrpdk.cn
http://af1xpkX2.qrpdk.cn
http://uFRh87jb.qrpdk.cn
http://2UgDJRnu.qrpdk.cn
http://HUTwanMH.qrpdk.cn
http://hggICNro.qrpdk.cn
http://Rwn1UTih.qrpdk.cn
http://XtBwuhYl.qrpdk.cn
http://YDJjoBNr.qrpdk.cn
http://5b5yPuOO.qrpdk.cn
http://90yDj86G.qrpdk.cn
http://0vGEDQHY.qrpdk.cn
http://6PIZBPRl.qrpdk.cn
http://yjPznObp.qrpdk.cn
http://yVbupqHq.qrpdk.cn
http://O9V9cHJC.qrpdk.cn
http://LFIZV3cv.qrpdk.cn
http://HwVn9hb2.qrpdk.cn
http://oojAY1Fu.qrpdk.cn
http://PQm4M7WU.qrpdk.cn
http://CNnCA2ko.qrpdk.cn
http://w3lxO9W4.qrpdk.cn
http://diqBkK3D.qrpdk.cn
http://4K5HawVt.qrpdk.cn
http://stKJrAt6.qrpdk.cn
http://WLBaNmVf.qrpdk.cn
http://YXZkU2qK.qrpdk.cn
http://r2UuFtMi.qrpdk.cn
http://Fjuzsosd.qrpdk.cn
http://gQ2XTzop.qrpdk.cn
http://www.dtcms.com/a/376683.html

相关文章:

  • 【大模型推理】Qwen2.5模型硬件要求与4090Ti多并发推理方案
  • Node 中进程与子进程的区别及使用场景
  • 【C++进阶系列】:万字详解红黑树(附模拟实现的源码)
  • 以供应链思维为钥,启数字化转型之门——读《供应链思维》有感
  • 体验访答浏览器
  • Zynq开发实践(FPGA之spi实现)
  • 2025年度总结
  • Redis 哨兵模式详解:实现高可用的自动故障转移方案
  • 电动汽车充电系统(EVCS)的入侵检测
  • 自定义事件发布器
  • 零基础学AI大模型之从0到1调用大模型API
  • vue3:调用接口的时候怎么只传递一个数组进去,得到一个key-value数据
  • Transformer 训不动:注意力 Mask 用反 / 广播错位
  • Prometheus部署监控实战
  • vue3引入海康监控视频组件并实现非分屏需求一个页面同时预览多个监控视频(2)
  • AGV 智能车驱动仓储效率提升:应用场景,智慧物流自动化实践指南
  • 【全栈实战】Elasticsearch 8.15.2 高可用集群部署与AI搜索全特性指南
  • Django REST Framework 构建安卓应用后端API:从开发到部署的完整实战指南
  • neo4j数据库创建范例(SQL文)
  • [rStar] docs | 求解协调器
  • WPF迁移avalonia之触发器
  • 【WPF+Prism】日常开发问题总结
  • 差异基因分析实战:手把手教你用R语言找到关键基因
  • 金融数据库--3Baostock
  • 【ICLR 2023】可逆列网络(RevCol)
  • Java SE 与常用框架
  • Web安全基石:深入理解与防御越权问题
  • 手写MyBatis第58弹:如何优雅输出可执行的SQL语句--深入理解MyBatis日志机制:
  • 2025流量新逻辑:AI × IP × 联盟|创客匠人
  • UGUI源码剖析(15):Slider的运行时逻辑与编辑器实现