欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程语言 > java >内容正文

java

【Java】关于Java中的各种流

发布时间:2024/7/5 java 49 豆豆
生活随笔 收集整理的这篇文章主要介绍了 【Java】关于Java中的各种流 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

1 IO流

1.1 概念

input:输入(读取)-----> 流:数据(字节/字符) -----> output:输出(写入)
输入:把硬盘中的数据,读取到内存中使用
输出:把内存中的数据,写入到硬盘中保存
内存:临时存储
硬盘:永久存储
1个字符 = 2个字节
1个字节=8个二进制位

顶层父类

输入流输出流
字节流字节输入流 InputStream字节输出流 OutputStream
字符流字符输入流 Reader字符输出流 Writer

2 字节流

2.1 字节输出流OutputStream

它是一个抽象类

共性成员方法:

  • public void close() :关闭此输出流并释放与此流相关联的任何系统资源。当完成流的操作时,必须调用此方法,释放系统资源。
  • public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
  • public void write(byte[] b) :将 b.length字节从指定的字节数组写入此输出流。
  • public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
  • public abstract void write(int b) :将指定的字节输出流。1次写1个字节。

  • 2.1.1 文件字节输出流FileOutputStream

    ,extends OutputStream,把内存中的数据写入硬盘的文件中。

    构造方法:创建一个 FileOutputStream 对象。根据参数传递的文件/文件路径,创建一个空文件。把 FileOutputStream 对象指向创建好的文件。

  • FileOutputStream(String name):文件路径
  • FileOutputStream(File file):文件

  • 写入数据的原理(内存 —> 硬盘)

    Java程序 —> JVM —>OS —> OS调用写数据的方法 —>把数据写入文件中

    字节输出流的使用步骤

  • 创建一个 FileOutputStream 对象,构造方法在传递写入数据的目的地
  • 抵用 FileOutputStream 对象的write方法,把数据写入文件中
  • 释放资源,清空流占用的内存,提高程序效率

  • 把a写入a.txt文件

    public abstract void write(int b)

    public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("a.txt");fos.write(97);fos.close();}

    原理:写数据时会把十进制97转为二进制1100001‬,硬盘中存储的数据都是字节,1个字节等于8个比特位。文本编辑器在打开文件时会查询编码表,把字节转为字符表示,97—>a。


    一次写入多个字节
    public void write(byte[] b)
    public void write(byte[] b, int off, int len) :把数组的一部分写入文件

    public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream(new File("b.txt"));byte[] a = {65,66,67,68,69};//ABCDEbyte[] b = {-65,-66,-67,68,69};//烤紻E//如果写的第一个字节是正数 显示会查ascii码表//如果是负数,第一个字节和第二个字节会组成一个中文显示 查询GBKfos.write(b);fos.write(a,1,2);//BCfos.close();}

    使用String类的方法把字符串转换为字节数组。

    public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream(new File("b.txt"));byte[] b = "哈哈哈".getBytes();System.out.println(Arrays.toString(b));fos.write(b);fos.close();}

    GBK:两个字节是一个中文
    UTF8:三个字节是一个中文


    数据的追加写和换行写
    追加写的构造方法 append=true
    FileOutputStream(String name, boolean append)
    FileOutputStream(File file, boolean append)
    换行:win【\r\n】mac【/n】linux【/r】

    public static void main(String[] args) throws IOException {//追加写FileOutputStream fos = new FileOutputStream(new File("b.txt"),true);for (int i = 0; i < 10; i++) {fos.write("哈哈哈".getBytes());//换行写fos.write("\r\n".getBytes());}fos.close();}

    2.2 字节输入流InputStream

    它是一个抽象类,是所有字节输入流类的超类
    共性方法

    • int read()
    • int read(byte[] b)
    • void close

    2.2.1 文件字节输入流FileInputStream

    作用:把硬盘中的数据,读取到内存中使用

    构造方法

    • FileInputStream(String name)
    • FileInputStream(File file)

    构造方法的作用

  • 创建一个FileInputStream对象
  • 把FileInputStream对象指向指定构造方法中要读取的文件

  • 读取数据原理(硬盘—>内存)
    Java程序 —> JVM —>OS —>OS调用读取数据的方法 —> 读取文件

    字节输出流的使用步骤

  • 创建FileInputStream对象,构造方法中绑定要读取的数据源
  • 调用FileInputStream对象的read方法,读取文件
  • 释放资源
  • 注意:read每调用一次指针都会后移一位,如果while循环括号中不保存读取的值,输出的就是跳位读取的值。

    一次读取一个字节

    public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("a.txt");int len = 0;while((len = fis.read())!=-1){//读取一个字节并返回 文件末尾返回-1System.out.print((char) len);}fis.close();}

    一次读取多个字节
    int read(byte[] b):
    注意:byte[]的作用是起缓冲作用,存储每次读取到的多个字节。数组长度一般定义为1024(1kb)或者1024的整数值。int返回值是每次读取的有效字节个数。

    原理:创建一个byte数组,数组元素的初始值为0。开始读取,把读取出的数据存入byte数组,指针移动,b.length是一次读取的字节个数。new String()可以把byte数组转换为字符串输出。read方法的返回值是有效读取字节个数。


    public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("a.txt");byte[] bytes = new byte[1024];int len = 0;while((len = fis.read(bytes))!=-1){System.out.print(new String(bytes,0,len));//打印byte中存的有效位}}

    2.3 字节流练习-文件复制

    原理
    创建一个输入流的对象,再创建一个输出流的对象,然后输入流对象读取文件内容,写入输出流指向的对象处。
    注意:应该先关闭输出流(写),再关闭输入流(读)。因为写完了一定读完了,但读完了不一定写完了。应该先开启输入流,再开启输出流,先读后写。

    public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("D:\\1.png");FileOutputStream fos = new FileOutputStream("E:\\1.png");byte[] bytes = new byte[1024];int len = 0;while((len=fis.read(bytes))!=-1){fos.write(bytes,0,len);}fos.close();fis.close();}

    2.4 字节流读文件存在的问题

    在读取中文字符的时候,可能不会显示完整的字符,因为一个中文可能占用多个字节。按字节流读取,每次只能读取字符的一部分。所以文本文件一般用字符流进行读写
    GBK:1个中文2个字节
    UTF8:1个中文3个字节

    3 字符流

    3.1 字符输入流Reader

    字符输入流类最顶层的父类,是一个抽象类。

    共性方法

    • int read()
    • int read(char[] c)
    • void close()

    3.1.1 文件字符输入流FileReader

    作用:把硬盘文件中的数据以字符的方式读取到内存中

    构造方法:创建一个FileReader对象,把FileReader对象指向要读取的文件/文件路径

    • FileReader(String name)
    • FileReader(File file)

    使用步骤

  • 创建FileReader对象,构造方法中绑定要读取的数据源
  • FileReader对象调用read方法
  • 关闭,释放资源
  • 一次读取一个字符

    public static void main(String[] args) throws IOException {FileReader fd = new FileReader("a.txt");int len = 0;while((len = fd.read())!=-1){System.out.print((char) len);}fd.close();}

    一次读取多个字符

    字符数组 —> 字符串 new String(char[], int off, int len)构造方法

    public static void main(String[] args) throws IOException {FileReader fd = new FileReader("a.txt");char[] c = new char[1024];int len = 0;while((len = fd.read(c))!=-1){System.out.print(new String(c,0,len));}fd.close();}

    3.2 字符输出流Writer

    共性方法

    • void write(int c) 写入单个字符。
    • void write(char[] cbuf) 写入字符数组。
    • abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
    • void write(String str) 写入字符串。
    • void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
    • void flush() 刷新该流的缓冲。
    • void close() 关闭此流,但要先刷新它。

    3.2.1 文件字符输出流FileWriter

    作用:内存中的字符数据写入文件中

    构造方法

    • FileWriter(String name)
    • FileWriter(File file)

    作用:创建FileWriter对象,根据构造方法中传递的文件/文件路径创建文件,会把FileWriter对象指向创建好的文件中。

    使用步骤

  • 创建FileWriter对象,构造方法中绑定写入数据的目的地。
  • 使用FileWriter中的方法write,把数据写入到内存缓冲区中。(字符转换为字节的过程)
  • 使用FileWriter中的方法flush,把内存缓冲区的数据,刷新到文件中。
  • 释放资源(会先把内存缓冲区的数据刷新到文件中)
  • 写入单个字符

    public static void main(String[] args) throws IOException {FileWriter fw = new FileWriter("a.txt");//绑定写入位置fw.write(97);//写入缓冲区 字符-->字节fw.flush();//写入文件fw.close();//释放资源}

    flush和close方法的区别
    close在关闭之前会先把内存缓冲区的数据刷新到文件中,但close之后不能继续使用write方法。flush同样也是刷新操作,但flush之后可以继续使用write方法。

    其他写入方法

    • void write(char[] c):写入字符数组
    • abstract void write(char[] c, int off, int len):写入字符数组的某一部分
    • void write(String str):写入字符串
    • void write(String str, int off, int len):写入字符串的某一部分
    public static void main(String[] args) throws IOException {FileWriter fw = new FileWriter("a.txt");char[] c = {'a','b','c','d','e','f'};fw.write(c);fw.write('\n');fw.write(c,3,3);String str = "嘻嘻哈哈呵呵";fw.write(str);fw.write('\n');fw.write(str,1,3);fw.close();}

    续写和换行写
    同字节流输出

    public static void main(String[] args) throws IOException {FileWriter fw = new FileWriter("c.txt",true);for (int i = 0; i < 10; i++) {fw.write("哈哈哈"+i);fw.write("\r\n");}fw.close();}

    4 IO流的异常处理

    在JDK1.7之前可以使用try-catch-finally处理流中的一次

    public static void main(String[] args) {FileWriter fw = null;try{fw = new FileWriter("F:\\c.txt",true);for (int i = 0; i < 10; i++) {fw.write("哈哈哈"+i);fw.write("\r\n");}}catch (IOException e){e.printStackTrace();}finally {if(fw != null){try {fw.close();} catch (IOException e) {e.printStackTrace();}}}}

    JDK7的新特性:可以在try后增加一个()( )(),括号中可以定义流对象,那么这个流对象的作用域就在try中有效,try执行完后,流对象自动释放,不用写finally【常用】

    public static void main(String[] args) {try(FileWriter fw = new FileWriter("F:\\c.txt",true)){for (int i = 0; i < 10; i++) {fw.write("哈哈哈"+i);fw.write("\r\n");}}catch (IOException e){e.printStackTrace();}System.out.println("哈哈哈哈哈");}

    JDK9的新特性,try前面可以定义对象,在try后边的()中可以引入流对象的名称。try执行完毕后,流对象可以释放掉,不需要写finally。【不常用】

    public static void main(String[] args) {FileReader fr = new FileReader("c.txt");FileWriter fw = new FileWriter("d.txt");try(fr;fw){char[] c = new char[1024];int len = 0;while((len = fr.read(c))!=-1){fw.write(c);}fw.flush();}catch (IOException e){e.printStackTrace();}System.out.println("哈哈哈哈哈");}

    5 属性集

    java.util.Properties 继承于Hashtable,来表示一个持久的属性集。是唯一一个和IO流相结合的集合。

    它使用键值结构存储数据,每个及其对应都是一个字符串。该类也被许多Java类使用,比如获取系统属性时, System.getProperties 方法就是返回一个Properties 对象。

    使用Properties存储数据并遍历取出

    操作字符串的特有方法

    • Object setProperty(String key, String value):相当于map.put(k, v)
    • String getProperty(String key):相当于map.get(k)
    • Set <String> stringPropertyNames():相当于map.keySet()
    public static void main(String[] args) {Properties prop = new Properties();prop.setProperty("张三","20");prop.setProperty("李四","25");prop.setProperty("王五","30");Set<String> set = prop.stringPropertyNames();for(String key: set){String value = prop.getProperty(key);System.out.println(key+" "+value);}}
    • 可以使用store方法把集合中的临时数据,持久化写入硬盘中存储
    • void store(OutputStream out, String comments):字节输出流,不能写中文
    • void store(Writer writer, String comments):字符输出流,可以写中文

    comments是注释,用来解释保存的文件是做什么的,不可以使用中文,默认是Unicode编码,一般使用空字符串

    使用步骤

  • 创建一个Proprorities对象,添加数据
  • 创建字节输出流/字符输出流对象,构造方法绑定输出位置
  • 使用store方法把集合中的临时数据持久化写入硬盘中。
  • 释放输出流对象
  • public static void main(String[] args) throws IOException {Properties prop = new Properties();prop.setProperty("张三","20");prop.setProperty("李四","25");prop.setProperty("王五","30");FileWriter fw = new FileWriter("e.txt");prop.store(fw, "");fw.close();}
    • 可以使用load方法,把硬盘中保存的文件,读取到集合中使用
    • void load(InputStream in):字节输入流,不能读取含有中文的键值对
    • void load(Reader r):字符输入流,可以读取含有中文的键值对

    使用步骤

  • 创建一个Properties对象,load堆区保存键值对的文件
  • 遍历Properties集合
  • 注意

    • 键值对文件中,键和值默认的连接符可以使用=、空格
    • 可以使用#来注释,被注释的键值对不会再读取
    • 键和值默认都是字符串,不用再加引号
    public static void main(String[] args) throws IOException {Properties prop = new Properties();prop.load(new FileReader("f.txt"));Set<String> set = prop.stringPropertyNames();for(String key: set){System.out.println(key+" "+prop.getProperty(key));}}

    6 缓冲流

    缓冲流,也叫高效流,是对4个基本的FileXxx 流的增强,所以也是4个流,按照数据类型分类:
    字节缓冲流: BufferedInputStream , BufferedOutputStream
    字符缓冲流: BufferedReader , BufferedWriter
    缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。

    6.1 字节缓冲流

    6.1.1 字节缓冲输出流BfferedOutputStream

    继承自OutputStream,可使用父类共性方法(见2.1)

    构造方法

    • BufferedOutputStream(OutputStream out):创建一个新的缓冲输出流,以数据写入指定的底层输出流。
    • BufferedOutputStream(OutputSteam out, int size):创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。

    使用步骤

  • 创建FileOutputStream对象,构造方法中绑定输出位置。
  • 创建BufferedOutputStream对象,构造方法中传递fos对象,提高fos对象效率。
  • 使用bos对象的write方法,把数据写入到内部缓冲区中。
  • 使用bos对象的flush方法,把缓冲区的数据刷新到文件中。
  • 释放资源,close会先调用flush刷新数据再关闭(所以第四步可省略)
  • public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("b.txt");BufferedOutputStream bos = new BufferedOutputStream(fos);bos.write("写入内部缓冲区".getBytes());//字节输出流 用字节bos.flush();bos.close();}

    6.1.2 字节缓冲输入流BfferedInputStream

    继承自InputStream,可使用父类共性方法(见2.2)

    构造方法

    • BufferedInputStream(InputStream in):创建一个新的缓冲输入流,保存参数输入流in。
    • BufferedInputStream(InputSteam in, int size):创建一个具有指定缓冲区大小的BufferedInputStream保存其参数,即输入流。

    使用步骤

  • 创建FileInputStream对象,构造方法中绑定读取位置。
  • 创建BufferedInputStream对象,构造方法中传递fis对象,提高fis对象的读取效率。
  • 使用bis对象的read方法,把数据写入到内部缓冲区中。
  • 释放资源。
  • public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("a.txt");BufferedInputStream bis = new BufferedInputStream(fis);/*int len = 0;while((len = bis.read()) != -1){System.out.print((char)len);}bis.close();*/byte[] bytes = new byte[1024];int len = 0;while((len = bis.read(bytes))!=-1){System.out.println(new String(bytes));}}

    6.1.3 基本和缓冲效率比较

    public static void main(String[] args) throws IOException {long s = System.currentTimeMillis();FileInputStream fis = new FileInputStream("D:\\1.png");FileOutputStream fos = new FileOutputStream("E:\\1.png");BufferedInputStream bis = new BufferedInputStream(fis);BufferedOutputStream bos = new BufferedOutputStream(fos);byte[] bytes = new byte[1024];int len = 0;while((len=bis.read(bytes))!=-1){bos.write(bytes,0,len);}bos.close();bis.close();long e = System.currentTimeMillis();System.out.println(e-s);}

    文件复制4MB的ppt的效率比较:

    基本流(一次读一个字节):17757 ms
    缓冲流(一次读一个字节):121 ms
    基本流 + 数组缓冲区(一次读多个字节):27 ms
    缓冲流 + 数组缓冲区(一次读多个字节):9 ms

    6.2 字符缓冲流

    6.2.1 字符缓冲输出流BufferedWriter

    继承自Writer,可使用父类共性方法(见3.2)

    构造方法

    • BufferedWriter(Writer out):创建一个使用默认大小输出缓冲区的缓冲字符输出流。
    • BufferedWriter(Writer out, int size):创建一个使用指定大小输出缓冲区的缓冲字符输出流。

    特有方法

    • void newLine():写入一个行分隔符,它会根据不同的操作系统,获取不同的行分隔符。

    使用步骤

  • 创建字符输出流对象,构造方法中传递写入地址
  • 创建字符缓冲区输出流对象,构造方法中传递字符输出流
  • 调用flush,将内存缓冲区中的数据刷新到文件中
  • 释放资源
  • public static void main(String[] args) throws IOException {BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));for (int i = 0; i < 10; i++) {bw.write("哈哈哈哈");bw.newLine();bw.write("嘻嘻嘻嘻");bw.newLine();}bw.close();}

    6.2.2 字符缓冲输入流BufferedReader

    继承自Reader,可使用父类共性方法(见3.1)

    构造方法

    • BufferedReader(Reader in):创建一个使用默认大小输入缓冲区的缓冲字符输入流。
    • BufferedReader(Reader in, int size):创建一个使用指定大小输入缓冲区的缓冲字符输入流。

    特有方法

    • String readLine():读取一行文本,读取一行数据,流末尾返回null,readLine不读换行符

    使用步骤

  • 创建字符输入流对象,构造方法中传递读取地址
  • 创建字符缓冲区输入流对象,构造方法中传递字符输入流
  • 调用read/readLine读取
  • 释放资源
  • public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new FileReader("b.txt"));String line = null;while((line = br.readLine())!=null){System.out.println(line);}}

    6.3 缓冲流练习-文本排序

    b.txt内容:
    7.77777777777777
    3.张三3333333333
    5.王五5555555555
    1.大一1111111111
    4.李四4444444444
    2.小二2222222222
    6.六六6666666666

    public static void main(String[] args) throws IOException {Map<String , String> map = new HashMap<>();BufferedReader br = new BufferedReader(new FileReader("b.txt"));BufferedWriter bw = new BufferedWriter(new FileWriter("nb.txt"));String line;while((line = br.readLine())!=null){String[] split = line.split("\\.");map.put(split[0],split[1]);}//map会自动排序for(String key: map.keySet()){String value = map.get(key);bw.write(key+"."+value);bw.newLine();}bw.close();br.close();}

    7 转换流

    7.1 字符编码和字符集

    字符编码
    计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。按照某种规则,将字符存储到计算机中,称为编码 。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码 。比如说,按照A规则存储,同样按照A规则解析,那么就能显示正确的文本f符号。反之,按照A规则存储,再按照B规则解析,就会导致乱码现象。

    字符编码Character Encoding : 就是一套自然语言的字符与二进制数之间的对应规则。

    字符集
    字符集 Charset :也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。计算机要准确的存储和识别各种字符集符号,需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBK字符集、Unicode字符集等。

    ASCII是最基本的编码表,GBK是中文编码表
    Unicode是万国码,兼容各种语言,是应用中优先采用的编码。

    7.2 编码常见问题

    例如:在IDEA中,使用FileReader 读取项目中的文本文件。由于IDEA的设置,都是默认的UTF-8编码,所以没有任何问题。但是,当读取Windows系统中创建的文本文件时,由于Windows系统的默认是GBK编码,就会出现乱码。

    解决方法:使用转换流

    7.3 转换流相关内容

    字节转换为字符(解码)
    FileInputStream —> 查询编码表 —> FileReader

    7.3.1 OutputStreamWriter

    字符流通向字节流的桥梁
    可以指定编码格式
    写入你想写入的编码格式的文件中

    构造方法

    • OutputStreamWriter(OutputStream out):创建使用默认字符编码的OutputStreamWriter(utf8)
    • OutputStreamWriter(OutputStream out, String charSet):创建使用指定字符编码的OutputStreamWriter

    使用步骤

  • 创建OutputStreamWriter对象,构造方法中传递字节输出流和指定编码集
  • 使用osw对象中的write,把字符转换为字节存在缓冲区中
  • 使用osw对象中的flush把字节刷新到文件中
  • 释放资源
  • 你好 GBK 4字节 UTF8 6字节

    public static void main(String[] args) throws IOException {OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk.txt"),"gbk");osw.write("你好");osw.close();}

    7.3.2 InputStreamReader

    字节流通向字符流的桥梁
    可以指定编码格式
    读取字节解码为字符 把看不懂的变成看得懂的

    构造方法

    • InputStreamReader(InputStream in):创建使用默认字符编码的OutputStreamWriter(utf8)
    • InStreamReader(InputStream in, String charSet):创建使用指定字符编码的InputStreamReader

    使用步骤

  • 创建InputStreamReader对象,构造方法中传递字节输入流和指定编码集
  • 使用isw对象中的read读取文
  • 释放资源
  • 注意:如果文件编码和指定编码不一致,则会发生乱码

    public static void main(String[] args) throws IOException {InputStreamReader isr = new InputStreamReader(new FileInputStream("utf8.txt"),"utf-8");int len = 0;while((len = isr.read())!=-1){System.out.print((char)len);}isr.close();}

    7.4 练习:转换文件编码

    将GBK编码的文本文件,转换为UTF8编码的文本文件

    public static void main(String[] args) throws IOException {InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk.txt"),"gbk");OutputStreamWriter osr = new OutputStreamWriter(new FileOutputStream("gbk2utf8.txt"),"utf-8");int len = 0;while((len = isr.read()) != -1){osr.write(len);}osr.close();isr.close();}

    8 序列化和反序列化

    8.1 概念

    ObjectOutputStream对象的序列化流
    把对象以流的方式写入到文件中保存,叫写对象,也叫对象的序列化。对象中包含的不仅是字符,使用字节流。

    ObjectInputStream对象的反序列化流
    把文件中的对象,以流的方式读取出来,叫读对象,也叫对象的反序列化。文件保存的都是字节,使用字节流。

    8.2 对象的序列化流ObjectOutputStream

    构造方法

    • ObjectOutputStream(OutputStream out)

    特有方法

    • void writeObject(Object obj)

    使用步骤

  • 创建ObjectOutputStream对象,构造方法中传递字节输出流
  • 使用writeObject方法写入对象
  • 释放资源
  • 序列化和反序列化时,会抛出NotSerializableException没有序列化异常。
    类通过实现Serializable接口以启动序列化功能,没有实现此接口的类无法使其任何状态序列化或反序列化。
    Serializable接口也叫标记型接口,进行序列化和反序列化,必须要实现Serializable接口,给类添加标记。在使用时,会检测是否有标记。

    使用前提
    Person类的实现 要加上implement Serializable

    public static void main(String[] args) throws IOException {ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"));oos.writeObject(new Person("张三",15));oos.close();}

    8.3 对象的反序列化流ObjectInputStream

    构造方法

    • ObjectInputStream(InputStream in)

    特有方法

    • void readObject(Object obj) 读取对象

    使用步骤

  • 创建ObjectOutputStream对象,构造方法中传递字节输入流
  • 使用writeObject方法读取对象
  • 释放资源
  • 打印对象
  • readObject方法声明抛出了ClassFoundException,class文件找不到异常,当不存在对象的class文件时抛出异常
    使用前提
    Person类的实现 要加上implement Serializable
    对象的class类文件要存在

    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Person.txt")); Object o = ois.readObject(); ois.close(); System.out.println(o);

    【注意!!!】
    InvalidClassException异常:序列化之后对类进行更改之后,不重新序列化,而是直接反序列化会出现异常。

    因为javac编译器会把java文件编译生成class文件。类如果实现了Serializable接口,就会根据类的定义给类的class文件添加一个序列化号serialVersionUID,输出的文件也会写入这个ID,反序列化的时候,会使用class文件的序列号和输出文件的序列号比较,如果ID一致,则反序列化一致,否则会抛出InvalidClassException异常

    而修改了类的定义之后,会给class文件重新编译生成一个新的序列号,但是输出文件的序列号没有改。

    解决方案:手动给类加一个序列号。无论是否修改类都不再修改序列号。

    自定义类中添加成员常量。

    private static final long serialVersionID = 1L;

    瞬态关键字transient
    static静态关键字:静态优先于非静态加载到内存中,(静态优先于对象),所以static修饰的成员变量是不能被序列化的,序列化的都是对象。
    【在上例中,如果Person类的age成员变量是静态的,序列化和非序列化age将永远是初始值0,无法更改】

    transient瞬态关键字:被它修饰的成员变量不能被序列化。如果想要对象中的成员变量不被序列化,可以使用瞬态关键字。

    8.4 练习:序列化集合

    当我们想在文件中保存多个对象的时候,可以把对象存在集合中,对集合进行序列化和反序列化。

    public static void main(String[] args) throws IOException, ClassNotFoundException {ArrayList<Person> list = new ArrayList<>();list.add(new Person("张三",15));list.add(new Person("李四",19));list.add(new Person("王五",20));ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("PersonList.txt"));oos.writeObject(list);ObjectInputStream ois = new ObjectInputStream(new FileInputStream("PersonList.txt"));Object o = ois.readObject();ArrayList<Person> list2 = (ArrayList<Person>) o;for (Person p : list2){System.out.println(p);}ois.close();oos.close();}

    9 打印流

    9.1 PrintSteam类

    平时我们在控制台打印输出,是调用print方法和println方法完成的,这两个方法都来自于java.io.PrintStream类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方式。

    特点

    • 不会抛出IO异常
    • 只负责输出,不负责读取
    • 特有方法print、println

    构造方法

    • PrintStream(File file):输出目的地是一个文件
    • PrintStream(OutputStream out):输出目的地是一个字节输出流
    • PrintStream(String path):输出目的地是一个文件路径

    注意

    • 如果用继承父类的write方法写数据,查看数据的时候就会查询编码表,再打印
    • 如果使用特有方法print和println则会原样输出
    public static void main(String[] args) throws IOException, ClassNotFoundException {PrintStream ps = new PrintStream("a.txt");ps.write(97);ps.write('\n');ps.println(97);ps.print("a1#$@哈哈哈");ps.close();}

    可以改变输出语句的目的地,即打印流的流向。
    输出语句,默认在控制台输出,使用System.setOut方向改变输出语句的目的地改为参数中传递的打印流的目的地。

    public static void main(String[] args) throws IOException, ClassNotFoundException {System.out.println("控制台输出:哈哈哈");PrintStream ps = new PrintStream("打印流输出");System.setOut(ps);System.out.println("打印流输出:哈哈哈");//控制台不输出这一句 而是写在"打印流输出"文件中}

    总结

    以上是生活随笔为你收集整理的【Java】关于Java中的各种流的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。