Java从入门到精通21==》字节流、字符流、序列化

Java从入门到精通21==》IO流、序列化

2023.8.13

文章目录

  • Java从入门到精通21==》IO流、序列化
    • 一、IO流简介
      • 总结===》IO分类
    • 二、字节流
      • 1、什么是字节流
      • 2、Java如何表示字节流
      • 3、 `close方法 `:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用
      • 4、字节输出流OutputStream
        • 1.什么是OutputStream
        • 2.如何使用OutputStream
        • 3、代码示例
      • 5、字节输入流InputStream
        • 1.什么是InputStream
        • 2.如何使用InputStream
        • 3.代码示例
    • 三、字符流
      • 1、什么是字符流
      • 2、Java如何实现
      • 3、 `flush方法` :刷新缓冲区,流对象可以继续使用。
      • 4、字符输出流Writer
        • 1.什么是字符输出流Writer
        • 2.如何使用Writer
        • 3.代码示例
      • 5、字符输入流Reader
        • 1.什么是Reader
        • 2.如何使用字符输入流Reader
        • 3.代码示例
    • 四、序列化
      • 1、什么是序列化
      • 2、ObjectOutputStream类
      • 3、ObjectInputStream类
      • 4、implements Serializable
        • 1.implements Serializable的作用
        • 2.implements Serializable如何获取id

一、IO流简介

IO流(Input/Output Stream)是Java中的一种输入输出机制,是处理输入输出流的一组类和接口的集合。在Java中,所有的输入输出都是通过流来实现的(即流指的是字符或字节流)。输入流用来从数据源中以某种方式读取数据,输出流用来向目标数据写入数据。IO流可以用来读写文件、网络连接、控制台输入输出等。Java中的IO流主要分为字节流和字符流两种类型。

总结===》IO分类

根据数据的流向分为:
输入流输出流

  • 输入流 :把数据从其他设备上读取到内存中的流,通常使用FileInputStream或BufferedInputStream来实例化。
  • 输出流 :把数据从内存 中写出到其他设备上的流,通常使用FileOutputStream或BufferedOutputStream来实例化。

格局数据的类型分为:
字节流字符流

  • 字节流 :以字节为单位,读写数据的流。

  • 字符流 :以字符为单位,读写数据的流。

二、字节流

1、什么是字节流

字节流(Byte stream)是一种数据流的形式,它以字节(byte)为单位进行传输
以字节为单位,读(输入)、写(输出)数据

2、Java如何表示字节流

在Java语言中,字节流是通过InputStream和OutputStream两个类实现的

  • 字节输出流:
    OutputStream
  • 字节输入流:
    InputStream

3、 close方法 :先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用

如果完成流的操作后没有释放系统资源,可能会导致以下问题:

  1. 内存泄漏:如果流操作涉及使用了大量的内存,没有释放资源可能会导致内存泄漏,最终导致系统运行缓慢或崩溃。
  2. 文件锁定:如果在文件读写操作完成后没有及时释放流资源,可能会导致文件被锁定,从而导致其他程序无法访问该文件。
  3. 系统崩溃:如果流操作是对底层系统资源进行操作,如网络连接、数据库连接等,没有及时释放资源可能会导致系统崩溃或无响应。

因此,在完成流操作后,一定要及时释放资源,避免以上问题的出现。可以使用try-with-resources语句或手动调用close()方法来关闭流并释放资源
注意:这是所以流操作都要注意的

4、字节输出流OutputStream

1.什么是OutputStream

java.io.OutputStream 抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法

2.如何使用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) :将指定的字节输出流。

注意:close方法,当完成流的操作时,必须调用此方法,释放系统资源。

3、代码示例

  1. 创建对象,并写入数据到文件
		//创建对象
        OutputStream os=new FileOutputStream("D:\\MMM.txt");
        //写数据 write(int b)  方法,每次可以写出一个字节数据
        os.write(97);
        os.write(98);
        os.write(99);
        os.close();

Java从入门到精通21==》字节流、字符流、序列化_第1张图片

  1. 写数据(数组方法) write(byte[] b) ,每次可以写出数组中的数据,这样效率跟高
OutputStream os = new FileOutputStream("D:\\MMM.txt");
        byte [] bytes="Java入门到精通".getBytes();
        os.write(bytes);
        os.close();

Java从入门到精通21==》字节流、字符流、序列化_第2张图片

  1. 写出指定长度字节数组,每次写出从off索引开始,len个字节
OutputStream os = new FileOutputStream("D:\\MMM.txt");
        byte[] bytes="aabbccddeee".getBytes();
        os.write(bytes,2,2);
        os.close();

Java从入门到精通21==》字节流、字符流、序列化_第3张图片

  1. 给文件中续写 , 换行
    \n : 换行符(newline),另起一行
    \r : 回车符(return),回到一行的开头
 OutputStream fos = new FileOutputStream("D:\\MMM.txt",true);
        String str="\nbcbc";
        fos.write(str.getBytes());
        fos.close();

Java从入门到精通21==》字节流、字符流、序列化_第4张图片

5、字节输入流InputStream

1.什么是InputStream

java.io.InputStream 抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。

2.如何使用InputStream

构造方法:
多态的手法
常用方法

  • public void close() :关闭此输入流并释放与此流相关联的任何系统资源。
  • public abstract int read(): 从输入流读取数据的下一个字节。
  • read():,读取字节,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回-1
  • read(byte[] b):每次读取b的长度个字节到数组中,返回读取到的有效字节个数
  • public int read(byte[] b): 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。

注意:close方法,当完成流的操作时,必须调用此方法,释放系统资源。

3.代码示例

  1. 实例化对象并从文件读取数据
package 字节输入流;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class Demo {
    public static void main(String[] args) throws IOException {
        //实例化InputStream是一个抽象类且是所以输入流类的超类
        InputStream is= new FileInputStream("D:\\mmm.txt");
        System.out.println((char) is.read());
        System.out.println((char) is.read());
        System.out.println((char) is.read());
        System.out.println((char) is.read());
        System.out.println((char) is.read());
        System.out.println((char) is.read());
        System.out.println((char) is.read());
        System.out.println((char) is.read());
        System.out.println((char) is.read());
        is.close();
        //因为-1在码表中没有对应的信息,所以打印方框
    }
}

Java从入门到精通21==》字节流、字符流、序列化_第5张图片

2.优化无数据问题
因为read方法,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回-1
所以可以根据read 的无返回值是否为-1作为判断条件看文件是否还有数据

InputStream is= new FileInputStream("D:\\mmm.txt");
 int a;
        while((a=is.read())!=-1){
            System.out.println((char) a);
        }
        is.close();

Java从入门到精通21==》字节流、字符流、序列化_第6张图片

  1. 使用read(byte[] b)读取数据
 InputStream is=new FileInputStream("D:\\MMM.txt");
        byte [] bytes =new byte[3];//定义数组装字节
        while (is.read(bytes)!=-1){
            //使用String构造方法把字节数组转换为字符串
            System.out.print(new String(bytes));
        }
        is.close();

Java从入门到精通21==》字节流、字符流、序列化_第7张图片

打印结构和实际结果不一样
分析原因:
最后一个数组没装满,使用只替换了两个个内容,而a没有被覆盖,使用也继续打印出来

  1. 优化
    因为read(byte[] b),每次读取b的长度个字节到数组中,返回读取到的有效字节个数
    所以定义一个个数,将byte数组中的被替换的个数记录下来
 InputStream is=new FileInputStream("D:\\MMM.txt");   
        int a;
        byte [] bytes =new byte[3];//定义数组装字节
        while ((a=is.read(bytes))!=-1){
            //使用String构造方法把字节数组转换为字符串
            System.out.print(new String(bytes,0,a));
        }
        is.close();

Java从入门到精通21==》字节流、字符流、序列化_第8张图片
注意:这里涉及到String的构造方法
Java从入门到精通21==》字节流、字符流、序列化_第9张图片

三、字符流

1、什么是字符流

字符流是指按字符为单位进行输入输出操作的数据流,以字符为操作单元,在编程中常用于文本文件的读写。字符流以字符为基本单位,将数据读入或写出程序。字符流分为字符输入流和字符输出流两种。

2、Java如何实现

在Java中,字符流主要由Reader和Writer类实现。

  • 字符输入流:
    Reader

  • 字符输出流:
    Writer

3、 flush方法 :刷新缓冲区,流对象可以继续使用。

刷新在一些特定场景下,IO流的刷新是非常必要的,比如:

  • 当使用多个输出流时,需要手工调用flush()方法才能确保数据被及时的输出到目标设备中。
  • 当程序需要及时地将数据输出到目标设备中时,或者需要保证数据的实时性时,就需要手工调用flush()方法。

总之,IO流的刷新虽然在一些场景下可能显得多余,但在一些特定的场景下是非常必要的,可以保证数据的有效性和完整性。

4、字符输出流Writer

1.什么是字符输出流Writer

Writer 抽象类是表示用于写出字符流的所有类的超类

2.如何使用Writer

构造方法:
多态手法
常用方法:

  • write(char[] cbuf, int off, int len): 将字符数组的一部分写入输出流
  • write(int c): 将单个字符写入输出流
  • write(String str, int off, int len): 将字符串的一部分写入输出流
  • write(String str): 将整个字符串写入输出流
  • write(char[] cbuf): 将整个字符数组写入输出流

3.代码示例

  1. 实例化对象并写入数据到文件
Writer ow=new FileWriter("D:\\nnn.txt");
        ow.write('中');
        ow.write('国');
        ow.close();

Java从入门到精通21==》字节流、字符流、序列化_第10张图片

  1. 写入字符数组,写入字符串,写入指定长度的数组
 Writer ow=new FileWriter("D:\\nnn.txt",true);
        //写入字符数组
        char [] chars1={10,'中','国','牛','毕','啊'};
        ow.write(chars1);
        //写入字符串
        String s="我也将很牛逼";
        ow.write(s);
        //写入字符串的某一部分,off字符串的开始索引,len写的字符个数
        char [] chars2={'中','国','牛','毕','啊'};
        ow.write(chars2,0,2);
        ow.close();

Java从入门到精通21==》字节流、字符流、序列化_第11张图片

5、字符输入流Reader

1.什么是Reader

Reader抽象类是表示用于读取字符流的所有类的超类

2.如何使用字符输入流Reader

构造方法:
多态手法
常用方法:

  • read():从输入流中读取下一个字符,返回其Unicode值,如果已经读取到流的末尾,则返回-1
  • read(char[] cbuf):从输入流中读取字符填充到指定的字符数组cbuf中,并返回实际读取的字符数
  • read(char[] cbuf, int off, int len):从输入流中读取字符填充到指定的字符数组cbuf中,并从数组的off位置开始,最多读取len个字符

3.代码示例

  1. 初始化,并读取文件信息
 public static void main(String[] args) throws IOException {
        //初始化
        Reader ir=new FileReader("D:\\NNN.txt");
        int a;
        while ((a= ir.read())!=-1){
            System.out.print((char)a);
        }
        ir.close();

Java从入门到精通21==》字节流、字符流、序列化_第12张图片

  1. 使用数组读取文件信息,注意读取数组覆盖的长度!
Reader ir=new FileReader("D:\\NNN.txt");
        int a;
        char [] chars=new char[2];
        while ((a= ir.read(chars))!=-1){
            System.out.print(new String(chars,0,a));
        }
        ir.close();
    }

Java从入门到精通21==》字节流、字符流、序列化_第13张图片
此操作和InputStream相似,具体细节可参考如何使用InputStream

四、序列化

1、什么是序列化

序列化是将对象转换为可存储或传输格式的过程。它的主要目的是将对象转换为字节流或文本格式,以便它可以被存储在磁盘上、传输到网络或其他程序中。反序列化则是将字节流或文本格式的序列化对象转换回对象本身的过程。

2、ObjectOutputStream类

ObjectOutputStream 序列化流,将Java对象的原始数据类型写出到文件,实现对象的持久存储
构造方法:
public ObjectOutputStream(OutputStream out) :
创建一个指定OutputStream的ObjectOutputStream

3、ObjectInputStream类

ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象
构造方法:
public ObjectInputStream(InputStream in) :
创建一个指定InputStream的ObjectInputStream。

4、implements Serializable

1.implements Serializable的作用

Java中的Serializable接口是一个标记接口,它没有任何方法。该接口的主要作用是标记一个类的对象可以被序列化(serialization),即可以将对象保存到磁盘或者通过网络传输给其他进程。
当一个类实现Serializable接口之后,它的对象就可以被序列化,即可以将对象转换为字节序列,然后将字节序列保存到磁盘或者通过网络传输给其他进程。反之,如果一个类没有实现Serializable接口,那么该类的对象就不能被序列化。
需要注意的是,Serializable接口只是一个标记接口,它并不会自动地将一个类的所有属性都序列化。如果需要将一个类的所有属性都序列化,需要在该类中添加相应的方法,比如writeObject和readObject方法。

2.implements Serializable如何获取id

在Java中,每个实现了Serializable接口的类都有一个唯一的序列化ID,用来标识该类的对象进行序列化和反序列化的版本号。这个ID可以自动生成,也可以手动指定。
自动生成ID的方式是使用Java提供的序列化工具,在编译时自动生成,生成的ID根据类的结构、成员变量、方法等因素计算得出,可以通过反射的方式获取到。例如:

long serialVersionUID = ObjectStreamClass.lookup(MyClass.class).getSerialVersionUID();
System.out.println("MyClass的序列化ID为:" + serialVersionUID);

手动指定ID的方式是在类中添加一个名为serialVersionUID的静态变量,并赋值为一个long型的数值。例如:

public class MyClass implements Serializable {
    private static final long serialVersionUID = 123456789L;
    // ...
}

需要注意的是,手动指定ID时必须确保该ID的唯一性,否则可能会导致序列化和反序列化时出现不兼容的情况。

若一个对象被序列化,他会默认得到一个id,但是每一次更改这个对象类,id都会发生改变,若想更改后任然可以被反序列化,就要设定固定的id。

你可能感兴趣的:(Java从入门到精通,java,开发语言,深度学习)