Java OOP 9 Java I/O

Java OOP 9 Java I/O

文章目录

  • Java OOP 9 Java I/O
        • 一、学习目标
        • 二、文件
        • 三、File类
        • 四、IO流
        • 五、Java流的分类
          • Java流的分类
          • 按流向划分:输入流和输出流
          • 按处理单元划分:字节流和字符流
          • 按流的角色划分:节点流和处理流
        • 六、字节流
          • 1、什么是字节流?
          • 2、字节输出流的基类:OutputStream
          • 3、字节输出流FileOutputStream类
          • 4、字节输出流FileOutputStream类应用示例
          • 5、字节输入流的基类:InputStream
          • 6、字节输入流FileInputStream类
          • 7、使用FileInputStream类按单字节读取数据
          • 8、使用FileInputStream类按多字节读取数据
        • 七、字符流
          • 1、问题:
          • 2、字符输出流的基类:Writer
          • 3、字符输出流FileWriter类
          • 4、字符输入流基类:Reader
          • 5、字符输入流FileReader类
        • 八、缓冲流
          • 2、BufferedWriter类
          • 3、使用 BufferedWriter 写文件
          • 4、BufferedReader类
        • 九、数据操作流
          • 1、数据操作流程简介
          • 2、DataOutputStream类
          • 3、DataInputStream类
          • 4、使用数据操作流读写二进制文件
        • 十、序列化与反序列化
          • 1、使用ObjectOutputStream类实现序列化
          • 2、使用ObjectInputStream类实现反序列化
        • 十一、IO流小结
        • 十二、本章总结

一、学习目标
  1. 会使用File类操作文件和目录
  2. 掌握IO流的基本概念和分类
  3. 掌握使用字节流读写文本文件
  4. 掌握使用字符流读写文本文件
  5. 掌握使用缓冲流读写文本文件
  6. 掌握使用数据操作流读写二进制文件
  7. 掌握使用对象流实现序列化和反序列化
二、文件

什么是文件?

  • 文件可认为是相关记录或放在一起的数据的集合

文件一般存储在哪里?

Java OOP 9 Java I/O_第1张图片

Java程序如何访问文件?

  • Java API :java.io.File
三、File类
  • File类是java.io包下代表操作与平台无关的文件和目录的类
  • 实现对文件或目录的新建、删除、重命名等操作

Java OOP 9 Java I/O_第2张图片

  • 一个File类的对象可以代表一个文件或目录
  • 可获取与文件相关的信息,如名称、修改日期、文件大小等

语法:

public File(String pathName);//pathName:文件路径
  • 绝对路径: 以根目录开头的完整路径

  • 相对路径: 相对于当前目录文件的路径

“.”表示当前目录

“…”表示上级目录

注意事项: Windows文件路径名中,分隔符可以使用正斜杠“/”,也可以使用反斜杠“\”。但必须写成“\\ ”,其中第一个“\”表示转义符

示例:

File file = new File("E:\\test.txt");//创建File类对象时,必须设置文件路径
  • File类的常用方法
方法名 描述
boolean createNewFile() 创建新文件
boolean delete() 删除文件
boolean exists() 判断文件是否存在
Boolean isFile() 判断是否是文件
boolean isDirectory() 判断是否是目录
long length() 返回文件长度,单位为字节 若文件不存在,则返回0L
String getPath() 返回此对象文件名所对应的路径
String getAbsolutePath() 返回此对象表示的文件的绝对路径名

File类应用示例1

在程序当前目录下创建非空文件test.txt,使用File类方法对该文件进行基本判断和操作

package com.aiden.io.demo01;

import java.io.File;

public class FileTest {
 public static void main(String[] args) {
     File file = new File("E:\\BDQN\\BCSP\\JavaCode\\T147JavaOOP\\JavaOOP09\\src\\test.txt");
     if (file.exists()) {
         if (file.isFile()) {
             System.out.println("文件名:" + file.getName() + ",文件长度:" + file.length() + "字节。");
             System.out.println("文件路径是:" + file.getPath());
             System.out.println("文件绝对路径是:" + file.getAbsolutePath());
         }
         if (file.isDirectory()) {
             System.out.println("此文件是目录");
         }
     } else {
         System.out.println("此文件不存在!");
     }
 }
}

运行结果

文件名:test.txt,文件长度:5字节。
文件路径是:E:\BDQN\BCSP\JavaCode\T147JavaOOP\JavaOOP09\src\test.txt
文件绝对路径是:E:\BDQN\BCSP\JavaCode\T147JavaOOP\JavaOOP09\src\test.txt

File类应用示例2

package com.aiden.io.demo02;

import java.io.File;
import java.io.IOException;

public class FileUtil {
    //创建文件
    public void createFile(File file) {
        if (file.exists()) {
            file.delete();
        } else {
            try {
                file.createNewFile();   //创建文件
                System.out.println("文件创建成功!");
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    //删除文件
    public void deleteFile(File file) {
        if (file.exists()) {
            file.delete();
            System.out.println("文件删除成功!");
        }
    }

    //输出文件信息
    public void print(File file) {
        if (file.exists()) {
            if (file.isFile()) {
                System.out.println("文件名:" + file.getName() + ",文件长度:" + file.length() + "字节。");
                System.out.println("文件路径是:" + file.getPath());
                System.out.println("文件绝对路径是:" + file.getAbsolutePath());
            }
            if (file.isDirectory()) {
                System.out.println("此文件是目录");
            }
        } else {
            System.out.println("此文件不存在!");
        }
    }
}

测试类

package com.aiden.io.demo02;

import java.io.File;

public class Test {
    public static void main(String[] args){
        FileUtil test = new FileUtil();
        File file = new File("D:\\doc\\test.txt");
        test.createFile(file);//创建文件
        test.print(file);//输出txt文件中的信息
        test.deleteFile(file);//删除
    }
}
四、IO流
  • File类能够实现对文件和目录的创建、删除等基础性操作,但是无法实现对文件的读写操作。如何读写文件?

  • IO流是指一连串流动的字符,以先进先出方式发送信息的通道

    • I:input,指读入操作
    • O:output,指写出操作
  • Java把所有流类型都封装到java.io包中,以实现输入/输出操作

    输入流

    Java OOP 9 Java I/O_第3张图片

    输出流

    Java OOP 9 Java I/O_第4张图片

五、Java流的分类
Java流的分类
  1. 按流向划分:输入流输出流
  2. 按处理单元划分:字节流字符流
  3. 按流的角色划分:节点流处理流

按流向划分:输入流和输出流

输入流

  • 只能从中读取数据,而不能写入数据的流,实现程序从数据源中读数据

Java OOP 9 Java I/O_第5张图片

输出流

  • 只能向其写入数据,而不能从中读数据的流,实现程序向目标数据源中写数据

Java OOP 9 Java I/O_第6张图片

输入流主要由InputStream和Reader作为基类

输出流则主要由OutputStream和Writer作为基类

都是抽象类,无法直接实例化对象

注意事项

​ 按照流的流向进行分类时,输入流完成数据读入操作,输出流完成数据写出操作,这里的“出”和“入”一定是从程序运行所在内存的角度来论述。


按处理单元划分:字节流和字符流

字节流

  • 以8位字节为操作数据单元的流,可操作二进制数据
  • 可细分为字节输入流、字节输出流

字符流

  • 以16位字符为操作数据单元的流,可操作文本数据
  • 可细分为字符输入流、字符输出流

Java OOP 9 Java I/O_第7张图片

区别

  • 操作的数据单元不同
  • 使用方法几乎相同

按流的角色划分:节点流和处理流

节点流

可以直接向一个特定的存储介质(如磁盘、文件)读写数据的流
使用节点流进行读写数据操作时,程序直接连接到数据源

Java OOP 9 Java I/O_第8张图片

处理流

对已存在的流进行连接和封装,通过封装后的流实现数据读写操作的流
使用处理流进行读写操作时,程序并不会直接连接到实际的数据源

Java OOP 9 Java I/O_第9张图片

使用处理流包装节点流,通过处理流执行输入和输出功能,让节点流与文件或磁盘等存储设置交互,可隐藏底层节点流的差异

六、字节流
1、什么是字节流?

具有输入和输出操作

主要操作byte类型数据

基类

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

2、字节输出流的基类:OutputStream

是抽象类,必须使用该类的子类进行实例化对象

常用方法

方法 描述
void close() 关闭输出流
void flush() 刷新缓冲区
void write(byte[] b) 将每个byte数组写入数据流
void write(byte[] b,int off,int len) 将每一个指定范围的byte数组写入数据流
void write(int b) 将一个字节数据写入数据流

如果需要操作文件,则使用FileOutputStream实例化


3、字节输出流FileOutputStream类

使用OutputStream类的FileOutputStream子类向文本文件写入数据

常用构造方法

方法 描述
FileOutputStream( File file) 创建向指定File对象写数据的文件输出流 file:指定目标文件的对象
FileOutputStream( String name) 创建向指定路径的文件写数据的文件输出流 name:指定目标文件的路径字符串
FileOutputStream( String name, boolean append) 创建一个向指定路径的文件写入数据的文件输出流 name:指定目标文件的路径字符串 append:表示是否在文件末尾追加数据。如果为true,则表示可以在文件末尾追加数据

创建文件输出流对象的常用方式

使用FileInputStream类按多字节读取数据//方式一:使用File对象构造对象
File file = new File("D:\\mydoc\\test.txt");
OutputStream fos = new FileOutputStream(file);
//方式二:使用文件路径构造对象
OutputStream fos = new FileOutputStream("D:\\doc\\test.txt");
//方式三:使用文件路径构造对象,且可向文件末尾追加数据
OutputStream fos = new FileOutputStream("D:\\doc\\test.txt"true);

4、字节输出流FileOutputStream类应用示例

需求:

  • 使用字节输出流向D:/doc/test.txt文件中写入字符串“I love Java! ”

实现步骤:

  1. 导入相关的类
  2. 构造文件输出流FileOutputStream对象
  3. 把数据写入文本文件
  4. 关闭文件输出流对象

关键代码

//1、导入相关的类
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
//2、构造文件输出流
OutputStream fos = null;
fos = new FileOutputStream("D:\\doc\\test.txt", true);
//3、将数据写入文本文件中
//准备一个字符串
String str = "I love Java!";
//将字符串转换为byte数组
byte[] words = str.getBytes();   
fos.write(words, 0, words.length);
System.out.println("文件已写入成功!");
//4、关闭文件输出流对象
if(fos != null) {
	fos.close();
}

注意事项

  • 创建输出流对象、执行写操作、关闭输出流时都可能会有IOException异常发生,因此,除处理FileNotFoundException异常外,还需处理IOException异常。
5、字节输入流的基类:InputStream
  • 从文件中读数据,与OutputStream一样,也是抽象类

常用方法

方法 描述
int read() 读取一个字节数据
int read(byte[] b) 将数据读取到字节数组中
int read(byte[] b,int off,int len) 从输入流中读取最多len长度的字节,保存到字节数组中,保存的位置从off开始
void close() 关闭输入流
int available() 返回输入流读取的字节数
6、字节输入流FileInputStream类

使用InputStream类的FileInputStream子类实现文本文件内容的读取

常用构造方法

方法 描述
FileInputStream(File file) 用于创建从指定File对象读取数据的文件输入流 file:指定目标文件数据源对象
FileInputStream(String name) 用于创建从指定路径的文件读取数据的文件输入流 name:指定目标文件数据源路径字符串

创建文件输入流对象的常用方式

//方式一:使用File对象构造对象
File file = new File("D:\\doc\\test.txt");
InputStream fis = new FileInputStream(file);
//方式二:使用文件路径构造对象
InputStream fis = new FileInputStream("D:\\doc\\test.txt");

从文件读取到计算机内存中的过程

Java OOP 9 Java I/O_第10张图片

read()方法

  1. 每次读取一个字节(0~255的整数)
  2. 每次读取多个字节

读取文件中全部数据

while( (data=fis.read()) != -1 ) {
   System.out.print((char)data);
}

注意事项

  1. 按字节读取并显示数据时需进行强制类型转换
  2. 使用read()读取文件中的数据时,当返回结果为-1时,即输入流已经读到末尾
  3. 在创建输入流对象、读取数据、关闭流时必须进行异常处理
7、使用FileInputStream类按单字节读取数据

从D:/doc/test.txt文件以字节为单元读取数据,输出到控制台

实现步骤:

  1. 导入相关类
  2. 构造文件输入流FilelnputStream对象
  3. 读取文本文件中的数据
  4. 关闭文件输入流对象
//1、导入相关类
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
//2、构造文件输入流
fis= new FileInputStream("D:\\doc\\test.txt");
System.out.println("可读取的字节数:"+ fis.available());
//3、读取文本文件中的数据
int data = 0;
System.out.println("文件的内容:");
while((data = fis.read()) != -1) {
 	System.out.print((char)data + " ");
}
//4、关闭文件输入流对象
if(fos != null) {
	fos.close();
}
8、使用FileInputStream类按多字节读取数据

需求:D:/doc/test.txt文件以多字节为单元读取数据,输出到控制台

分析:

  • 使用read()重载方法,实现每次读取多个字节,如:read(byte[] b)

关键代码

fis= new FileInputStream("D:\\doc\\test.txt");
//执行读操作
byte[] words = new byte[1024];
int len = 0;//实际读取长度
while( (len = fis.read(words)) > 0 ) {//读取数据,获取实际长度
	//按实际长度输出数据,避免出现多余的空白
    System.out.println(new String(words, 0, len ));
}

常见错误

假设 D:/doc/test.txt文件

l love Java!l love Java!
—种新技术—旦开始流行,你要么坐上压路机,要么成为铺路石。

说出下面代码的执行结果

fis= new FileInputStream("D:\\doc\\test.txt");
byte[] words = new byte[21];//长度是21字节数组,不能一次读取全部数据
int len = 0;
while( (len = fis.read(words)) > 0 ) {
    System.out.println(new String(words, 0, len ));
}

结论:

  1. 文本文件保存时,采用GBK编码方式,每个中文占2个字节
  2. read()方法一次读取1个字节(半个中文字符)
  3. 当数组长度不足时,可能导致中文乱码
七、字符流
1、问题:
  • 一个字符占用内存的两个字节
  • 如果用字节流处理文本文件,需要将字节转换成字符,会降低程序的执行效率,怎么办?
    • 当输入和输出是文本文件时,尽量使用字符流
    • 使用Reader类和Writer类操作字符
  • 基类
    • 字符输出流类:Writer
    • 字符输入流类:Reader
  • 使用字符流读写文本更合适

2、字符输出流的基类:Writer
  • 抽象类

  • 常用方法

    方法 描述
    void write(String str) 将str字符串中包含的字符输出到输出流中
    void write(String str, int off, int len) 将字符串中从off位置开始,长度为len的字符输出到输出流中
    void close() 关闭输出流
    void flush() 刷新输出流

3、字符输出流FileWriter类

概念:

  • FileWriter类是Writer类的子类
  • 以字符为数据处理单元向文本文件中写数据

示例:

  • 将字符串写入D:/doc/mysaying.txt文件

实现步骤:

  1. 导入相关的类
  2. 创建FileWriter对象
  3. 使用write方法向文本文件写数据
  4. 清空流 关闭流
//1、导入相关的类
import java.io.Writer;
import java.io.FileWriter;
import java.io.IOException;
Writer fw = null;
try {
     //2.创建FileWriter对象
     fw = new FileWriter("D:\\doc\\mysaying.txt");
     //3.使用write方法向文本文件写数据
     fw.write("预测未来的最好方式就是创造未来!");
     fw.flush();//刷新缓冲区
     System.out.println("文件写入成功!");
} catch (IOException ex) {
    //....
} finally {
     //4.清空流 关闭流
     if(fw!=null) {
         try {
                 fw.close();
             } catch(IOException ex) {
                 ex.printStackTrace();
             }
     }
}

4、字符输入流基类:Reader
  • 是抽象类

  • 常用方法

    方法 描述
    int read() 从输入流中读取单个字符,返回所读取的字符数据
    int read(char[] c) 从输入流中最多读取c.length个字符数据,并将其存储在字符数组c中,返回实际读取的字符数
    int read(char[] c, int off, int len) 从输入流中最多读取len个字符的数据,并将其存储在字符数组c中 存入数组c中时,并不是从数组起点开始,而是从off位置开始,返回实际读取的字符数

5、字符输入流FileReader类
  • FileReader是Reader类的子类

需求:

  • 从“D:/doc/诗词.txt”中读取数据,显示到控制台

实现步骤:

  1. 导入相关的类
  2. 创建FileReader对象
  3. 循环使用read()方法读取文件中数据
  4. 关闭流
import java.io.FileReader;
import java.io.Reader;
import java.io.FileNotFoundException;
import java.io.IOException;
Reader fr = null;
try {
    //创建对象
	fr = new FileReader("D:\\doc\\诗词.txt");
    char[] ch = new char[1024]; 
    int len = 0;
    //读取数据
    while((len = fr.read(ch)) > 0) {
         System.out.println(new String(ch,0,len));
    }
}catch (FileNotFoundException ex) { 
    //省略异常处理代码
}finally {
    //关闭流
	fr.close();
}
八、缓冲流

1、问题

  • 如何提高读写文件数据的执行效率?

    • java.io包提供了缓冲流
  • Java缓冲流自身并不具有IO功能,只是在别的流上增加缓冲,以提高程序性能

  • 分类

    • 字节缓冲流
    • 字符缓冲流
      • BufferedWriter
      • BufferedReader

    Java OOP 9 Java I/O_第11张图片

  • 这里我们以字符缓冲流为例,介绍缓冲流的用法

  • BufferedReader类的缓冲区(它可以先把一批数据读到缓冲区,接下来的读操作都是从缓冲区内获取数据,避免每次都从数据源读取数据进行字符编码转换,从而提高读取操作的效率)

2、BufferedWriter类
  • 是Writer类的子类
  • 带有缓冲区
  • 默认情况下,只有缓冲区满的时候,才会把缓冲区的数据真正写到目的地,能减少物理写数据的次数,提高输入/输出操作的执行效率
  • 常用的构造方法
方法 描述
BufferedWriter(Writer out) 创建一个缓冲字符输出流
  • 使用FileWriter类与BufferedWriter类,可提高字符流写文本文件的效率
3、使用 BufferedWriter 写文件

示例:

  • 使用BufferedWriter类对象向文本文件D:/doc/buff.txt中写数据

实现步骤:

  1. 导入相关的类
  2. 构造FileWriter对象和BufferedWriter对象
  3. 调用write()方法写数据
  4. 清空、关闭流对象
//1.导入相关的类
import java.io.FileWriter ;
import java.io.BufferedWriter ;
import java.io.IOException;
Writer fw = null;
BufferedWriter bw = null;
try {
  //2.构造FileWriter对象和BufferedWriter对象
  fw = new FileWriter("D:\\doc\\buff.txt");
  bw = new BufferedWriter(fw); 
  //3.调用write()方法写数据
  bw.write("亲爱的小伙伴们:");
  bw.newLine();//插入一个换行符
  bw.write("让我们来使用缓冲流让程序加速吧!");
  bw.flush();//刷新缓冲区
  System.out.println("文件写入成功!")
}cath(Exception e){
    //...
}
//4.清空、关闭流对象
bw.close();
fw.close();

4、BufferedReader类
  • BufferedReader类是Reader类的子类

  • 带有缓冲区,提高文件读取的效率

  • 把一批数据读到缓冲区

  • 从缓冲区内获取数据

  • 常用构造方法

    方法 描述
    BufferedReader(Reader in) 创建一个缓冲字符输入流
  • readLine()方法

    • 按行读取文件中数据

示例:

  • 读取文本文件D:/doc/buff.txt中数据,并输出

实现步骤:

  1. 导入相关的类
  2. 构造FileReader对象和BufferedReader对象
  3. 调用readLine()方法读取数据
  4. 清空、关闭流对象

代码实现:

//1.导入相关的类
import java.io.FileReader;
import java.io. BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
//2.构造FileReader对象和BufferedReader对象
Reader fr = null;                            
BufferedReader br = null; 
//省略try块 
 fr = new FileReader("D:\\doc\\buff.txt");
 br = new BufferedReader(fr);
//3.调用readLine()方法读取数据 
String line = br.readLine();             
 while(line != null) {
     System.out.println(line);            
     line = br.readLine();
 }
//4.清空、关闭流对象
if(br != null)  br.close();                      
if(fr != null)  fr.close();
九、数据操作流
1、数据操作流程简介
  • 数据操作流主要实现对二进制文件读写操作
  • 分类
    • DataOutputStream类
      • OutputStream类的子类
      • 与FileOutputStream类结合使用写二进制文件
    • 使用DataOutputStream类写二进制文件的实现步骤与FileOutputStream类写文本文件相似
    • DataInputStream类
      • InputStream类的子类
      • 与FileInputStream类结合使用读取二进制文件
    • 使用DataInputStream类读取二进制文件的实现步骤与FileInputStream类读取文本文件相似

2、DataOutputStream类
  • 按照与平台无关的方式向流中写入基本数据类型的数据

    • 如int、float、long、double和boolean等
  • 使用writeUTF()方法能写入采用utf-8字符编码的字符串

    FileOutputStream out1 = new FileOutputStream("D:\\doc\\test.txt");		
    BufferedOutputStream out2 = new BufferedOutputStream(out1);
    DataOutputStream out = new DataOutputStream(out2);
    out.writeByte(1);
    out.writeLong(2);
    out.writeChar('c');
    out.writeUTF("hello");
    

3、DataInputStream类
  • 按照与平台无关的方式从流中读取基本数据类型的数据

    • 如int、float、long、double和boolean等
  • 使用readUTF( )方法能读取采用utf-8字符编码的字符串

    FileInputStream in1 = new  FileInputStream("D:\\doc\\test.txt");		
    BufferedInputStream in2 = new BufferedInputStream(in1);
    DataInputStream in = new DataInputStream(in2);
    System.out.println(in.readByte());
    System.out.println(in.readLong());
    System.out.println(in.readChar());
    System.out.println(in.readUTF());
    
4、使用数据操作流读写二进制文件

示例:

  • 读取二进制文件D:/doc/User.class数据,写入二进制文件D:/doc/newUser.class

核心代码:

DataOutputStream dos = null;
DataInputStream dis = null;
FileInputStream fis= null;
FileOutputStream fos=null;
try {
    //创建输入流文件
    fis = new FileInputStream("D:\\doc\\User.class");
    dis = new DataInputStream(fis);
    //创建输出流文件
    fos = new FileOutputStream("D:\\doc\\newUser.class");
    dos = new DataOutputStream(fos);
    int temp;
    while(((temp=dis.read()) != -1)) {//读取文件中二进制数据
        fos.write(temp);//向文件写二进制数据	
    }
} catch(Exception ex) {
    ex.printStackTrace();
} finally {
     //省略异常处理代码
     dis.close();
     fis.close();
     fos.close();
     dos.close();
}
十、序列化与反序列化

问题:

  • 为每个对象属性一一编写读写代码,过程很繁琐且非常容易出错,如何解决?

方案:

  • 使用序列化和反序列化,方便数据传输和存储

概念:

  • 序列化是将对象的状态存储到特定的存储介质中的过程,

  • 反序列化是将特定的存储介质中数据重新构建对象的过程

    Java OOP 9 Java I/O_第12张图片

    对象输出流( ObjectOutputStream ):实现序列化
    对象输入流( ObjectInputStream):实现反序列化


1、使用ObjectOutputStream类实现序列化
  • 序列化的对象所属类须为可序列化的类

  • 一个类实现java.io.Serializable接口,该类的对象是可序列化的

    //一个标识接口
    public interface Serializable{}
    
  • JDK1.8类库中,有些类实现了java.io.Serializable接口

    • 如:String类、包装类和日期时间类等
  • 创建一个Person类,并标记该类的对象是可序列化的

    import java.io.Serializable;
    public class Person implements Serializable {
        private String name;
        private int age;
        private String sex;
        //省略getter/setter
        public void print() {
            System.out.println("姓名:"+this.name+",年龄:"+this.age+",性别:"+this.sex+"。");
        }
    }
    
  • 常用方法

    方法 描述 类型
    ObjectOutputStream(OutputStream out) 创建对象输出流对象 构造方法
    final void writeObject(Object obj) 将指定对象写入流 实例方法

    如何解决序列化和反序列化的版本不一致问题?

  • 引入serialVersionUID常量

  • serialVersionUID常量为long类型

  • JVM在编译时自动生成serialVersionUID常量,也可显式定义

  • 在Person类中显式定义serialVersionUID常量

    import java.io.Serializable;
    public class Person implements Serializable {
        //serialVersionUID常量
        private static final long serialVersionUID=1L;
        
        private String name;
        private int age;
        private String sex;
        public void print() {
            System.out.println("姓名:"+this.name+",年龄:"+this.age+",性别:"+this.sex+"。");
        }
    }
    

序列化对象示例

实现步骤:

  1. 导入相关的类
  2. 创建可序列化的类,要求实现Serializable接口
  3. 创建对象输出流(ObjectOutputStream)
  4. 输出可序列化对象
  5. 关闭对象输出流
//1.导入相关的类
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
//2.创建可序列化的类,要求实现Serializable接口
public class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    //…
}
//3.创建对象输出流(ObjectOutputStream)
ObjectOutputStream oos = null;
//省略异常处理代码
oos = new ObjectOutputStream(
new FileOutputStream("D:\\doc\\person.bat"));
//4.输出可序列化对象
Person person = new Person("杰米", 25, "男");
oos.writeObject(person);//对象序列化,写入输出流
//5.关闭对象输出流
if(oos!=null) {
	//省略异常处理代码
	oos.close();
}

序列化集合示例

ObjectOutputStream oos = null;
try {
    oos = new ObjectOutputStream(new FileOutputStream("D:\\doc\\persons.bat"));
    Person person = new Person("杰米", 25, "男");
    Person person2 = new Person("Lisa", 30, "女");
    ArrayList<Person> list = new ArrayList<Person>();
    list.add(person);
    list.add(person2);
    oos.writeObject(list);//集合对象序列化
    System.out.println("序列化成功!");
}catch(IOException ex){
    ex.printStackTrace();
}finally {
    if(oos!=null){
         try{
             oos.close();
         }catch(IOException ex){
             ex.printStackTrace();
         }
    }
}

2、使用ObjectInputStream类实现反序列化
  • 使用对象输出流ObjectInputStream可以还原序列化的对象

  • 常用方法

    方法 描述 类型
    ObjectInputStream(InputStream in) 创建对象输入流对象 构造方法
    final Object readObject() 从指定位置读取对象 实例方法

    readObject() 返回一个Object类型的对象,如果确定该Object对象的真实类型,则可以将该对象强制转换成其真实类型

反序列化对象示例

需求

  • 读取D:/doc/person.bat文件中一个Person对象的数据

实现步骤

  1. 导入相关的类
  2. 创建一个对象输入流(ObjectInputStream)
  3. 输出反序列化后对象信息
  4. 关闭对象输入流
//1.导入相关的类
import java.io.ObjectInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
//2.创建一个对象输入流(ObjectInputStream)
ObjectInputStream ois = null;
//省略异常处理代码
ois = new ObjectInputStream(new FileInputStream("D:\\doc\\person.bat"));
//3.输出反序列化后对象信息
//反序列化时,readObject()方法返回的是Object对象需强制类型转换为Person对象
Person per = (Person) ois.readObject();
per.print();
//4.关闭对象输入流
if (ois != null)  ois.close();

反序列化集合示例

ObjectInputStream ois = null;
try {
      ois = new ObjectInputStream(new FileInputStream("D:\\doc\\persons.bat"));
      ArrayList<Person> list = (ArrayList<Person>)ois.readObject();
      for(Person person:list) {
           person.print();
      }
}catch(ClassNotFoundException ex) {
     ex.printStackTrace();
} catch(FileNotFoundException ex) {
     ex.printStackTrace();
} catch (IOException e) {
     e.printStackTrace();
} finally {
     try {
         if (ois != null) ois.close();
     }catch (IOException ex) {
          ex.printStackTrace();
     }
}

限制序列化

问题:

  • 出于安全考虑,对于一些比较敏感的信息(如用户密码),应限制被序列化,如何实现?

方案:

  • 使用transient关键字修改不需要序列化的对象属性

示例:

  • 希望Person类对象中的年龄信息不被序列化
import java.io.Serializable;
public class Person implements Serializable {
    private String name;
    private transient int age;//使用transient关键字修改不需要序列化的对象属性
    private String sex;
    public void print() {
        System.out.println("姓名:"+this.name+",年龄:"+this.age+",性别:"+this.sex+"。");
    }
}
十一、IO流小结

Java常用IO流有哪些?

分类 字节输出流 字节输入流 字符输出流 字符输入流
基类 OutputStream InputStream Writer Reader
文件流 FileOutputSteam FileInputStream FileWriter FileReader
缓冲流 BufferedOutputStream BufferedInputStream BufferedWriter BufferedReader
对象流 ObjectOutputStream ObjectInputStream - -
数据操作流 DataOutputStream DataInputStream - -
  • 所有的基类都是抽象类,无法直接创建实例,需要借助其实现类
  • 所有输出流实现写数据,所有输入流实现读数据
  • 输入和输出是相对程序而言
  • 所有的文件流直接与存储介质关联,需指定物理节点

经验:

  1. 在操作文本文件时,应使用字符流
  2. 字节流可以处理二进制数据,它的功能比字符流更强大
  3. 如果是二进制文本,应考虑使用字节流
十二、本章总结

你可能感兴趣的:(Java,OOP,java)