第四章、第4节 IO

文章目录


I : in(输入,读取) O : out (输出,写出)

对于需要掌握的内容:

  1. 文件的增、删、改及查找等操作。
  2. 对文件字节上数据的读取和写出。
  3. 对文本文件字符上的读取和写出。

一、java.io.File

描述:文件或目录路径的抽象表示。

1、字段(与系统相关,便于跨平台)

变量和类型字段描述
static StringpathSeparator与系统相关的路径分隔符,以字符串形式体现。
static charpathSeparatorChar与系统相关的路径分隔符,以字符形式体现。
static Stringseparator系统相关的默认名称分隔符,以字符串形式体现。
static charseparatorChar系统相关的默认名称分隔符,以字符形式体现。

eg:File.separator; //在UNIX系统上是’/’,而在Windows系统上是’\\’。(区别)

2、构造方法

构造器描述
File(String pathname)通过将给定的路径名字符串转为抽象路径名来创建新的File实例。
File(File parent , String child)从父抽象路径名和子路径名字符串创建新的File实例。
File(String parent , String child)从父路径名字符串和子路径名字符串创建新的File实例。

3、成员方法

常用方法

变量和类型方法描述
booleanexists()测试此抽象路径名表示的文件或目录是否存在。【创建文件前建议先使用exists()方法判断】
booleancreateNewFile()仅当此名称文件不存在时,创建由此抽象路径命名的新空文件。
booleanmkdir()创建此抽象路径名指定的一级目录(即一个文件夹)。
booleanmkdirs()创建此抽象路径名指定的一级或多层目录(即一个或多层文件夹)。
booleandelete()删除此抽象路径名表示的文件或目录。
voiddeleteOnExit()请求在JVM终止时删除此抽象路径表示的文件或目录。
booleanrenameTo(File dest)重命名此抽象路径名表示的文件。【兼重命名+剪切功能】
longlength()返回此抽象路径名表示的文件的长度。【单位:字节(byte)】
String[]list()返回一个字符串数组,用于命名此抽象路径名表示的目录中的文件或目录。
String[]list(FilenameFilter filter)返回一个字符串数组,用于命名此抽象路径名表示的目录中的文件或目录,以满足指定的过滤器。
File[]listFile()返回一个抽象路径名数组,表示此抽象路径名表示的目录中的文件或目录。
File[]listFile(FilenameFilter filter)返回一个抽象路径名数组,表示此抽象路径名表示的目录中满足过滤器的文件或目录。
FilegetAbsoluteFile()返回此抽象路径名的绝对形式。
StringgetAbsolutePath()返回此抽象路径名的绝对路径名字符串。(常用)
FilegetCanonicalFile()返回此抽象路径名的规范形式。
StringgetCanonicalPath()返回此抽象路径名的规范路径名字符串。
StringgetName()返回此抽象路径名表示的文件或目录的名称。
StringgetParent()返回此抽象路径名父项的路径名字符串,若此路径未指定父目录,则返回null。
FilegetParentFile()返回此抽象路径名父项的抽象路径名,若此路径未指定父目录,则返回null。
StringgetPath()将此抽象路径转为路径名字符串。
booleanisAbsolute()测试此抽象路径名是否为绝对路径。
booleanisDirectory()测试此抽象路径名表示的文件是否为目录(即文件夹)。
booleanisFile()测试此抽象路径名指定的文件是否为普通文件。

其他方法

变量和类型方法描述
booleancanExecute()测试应用程序是否可以(执行)此抽象路径名表示的文件。
booleancanRead()测试应用程序是否可以(读取)此抽象路径名表示的文件。
booleancanWrite()测试应用程序是否可以(修改)此抽象路径名表示的文件。
intcompareTo(File pathname)按字典顺序比较两个抽象路径名。(三种情况:正、0、负)

二、相对与绝对路径

路径:用于描述文件的地址。

1、绝对路径

​ 从盘符开始是一个完整的路径。例如:“C:\\a.txt”

特点:完整 且 固定。

2、相对路径

​ 在Java中是相对于项目目录路径(当前项目中),这是一个不完整的便捷路径,在Java开发中很常用。例如:“a.txt”

特点:不含盘符,不完整非固定。

三、IO流概述

​ 可将数据传输的操作,看作一种数据的流动,按照流的方向分为输入Input和Output。

​ Java中的 IO 操作主要指的是java.io包下的一些常用类的使用。通过这些常用类对数据进行读取(输入Input)和写出(输出Output)。

IO流的分类:

​ 按照流的方向来分,可分为:输入流和输出流。

​ 按照流的数据类型来分,可分为:字节流(读取网页数据,常用)和字符流(面向文字,解决乱码)。其他较常用的打印流,对象流 … …

字节流(顶级父类):

​ ——输入流:InputStream(读取)

​ ——输出流:OutputStream(写出)

字符流(顶级父类):

​ ——输入流:Reader(读取)

​ ——输出流:Writer(写出)

首先明确,一切皆字节:

​ 在计算机中的任何数据(文本、图片、视频、音乐等等)都是以二进制形式存储的。在数据传输时,也都是以二进制的形式存放的。

​ 后续学习的任何流,在传输时底层都是二进制。

1、字节输出流

1-1、java.io.OutputStream【字节的输出流】

​ OutputStream是一个抽象类,不能直接创建对象,需借助继承它的子类。

1-1-1、常用方法
变量和类型方法描述
voidclose()关闭此输出流并释放与此流关联的所有系统资源。【重点】
voidflush()刷新此输出流并强制写出任何缓冲的输出字节。
voidwrite(byte[] b)将b.length字节从指定的字节数组写入此输出流。
voidwrite(byte[] b,int off,int len)将从偏移量off开始的指定字节数组中的len字节写入此输出流。
abstract voidwrite(int b)将指定的字节写此输出流。
1-1-2、其他方法
变量与类型方法描述
static OutputStreamnullOutputStream()返回一个新的OutputStream,它丢弃所有字节。
1-2、java.io.FileOutputStream【文件输出流】

​ FileOutputStream类继承的OutputStream类。

1-2-1、常用构造方法
构造器描述
FileOutputStream(File file)创建文件输出流以写入由指定的File对象表示的文件。
FileOutputStream(File file,boolean append)创建文件输出流以写入由指定的File对象表示的文件。append = true,追加;相反不追加。
FileOutputStream(String name)创建文件输出流以写入具有指定名称的文件。
FileOutputStream(String name,boolean append)创建文件输出流以写入具有指定名称的文件。append = true,追加;相反不追加。
1-2-2、方法用父类的

2、字节输入流

2-1、java.io.InputStream【字符输入流】

​ InputStream类也是一个抽象类,需继承它的子类实例化对象。

2-1-1、常用方法
变量和类型方法描述
voidclose()关闭此输入流并释放与该流关联的所有系统资源。【重点】
abstract intread()从输入流中读取下一个数据字节。
intread(byte[] b)从输入流中读取一组数据字节并将它们存储到缓冲区数组b。【特常用】
2-1-2、其他方法
变量和类型方法描述
intread(byte[] b,int off,int len)从偏移量off开始最多len字节的数据读入一个字节数组。
2-2、java.io.FileInputStream【文件输入流】

​ FileInputStream类继承了InputStream类。

2-2-1、常用构造器
构造器描述
FileInputStream(File file)通过打开与实际文件的连接来创建FileInputStream,该文件由文件系统中的File对象file命名。
FileInputStream(String name)通过打开与实际文件的连接来创建FileInputStream,该文件由文件系统中的路径名name命名。
2-2-2、常用方法与父类类同

3、字符编码

3-1、UTF-8(万国码)

​ UTF-8是一个(1~4)字节动态可变的字符编码,其编码长度随当前字符大小而定。

原理:

  1. 当需要1个字节时,需要8个二进制位对其进行编码;
  2. 当需要2个字节时,需要16个二进制位对其进行编码;
  3. 当需要3个字节时,需要24个二进制位对其进行编码;
  4. 当需要4个字节时,需要32位二进制位对其进行编码。

乱码:数据的输入方与输出方持有不同的编码。

例如:
    A持有GB2312编码规则,B持有ASCII编码规则。
    ∵ ASCII编码域为0~255(基本的字符集),GB2312编码(含基本字符集及高纬度字符集)
    ∴ 当对非基本字符(且∈GB2312编码集),对其编码时采用ASCII编码将产生乱码,而GB2312对其编码则不会。
(属于个人理解)

解决方案:对于不同字符集(语言、符号等)建议采用UTF-8对其编码。因UTF-8包含全世界所有国家需要用到的字符,是国际编码,通用性强。

4、字符输出流

4-1、java.io.Writer【字符的输出流】

​ Writer类是一个抽象类,需要继承它的子类实例化对象。

4-1-1、常用方法
变量和类型方法描述
Writerappend(char c)将指定的字符追加到此writer。
abstract voidclose()关闭流。
abstract voidflush()刷新流。
voidwrite(char[] cbuf)写一个字符数组。
voidwrite(char[] cbuf,int off,int len)写一个字符数组的一部分。
voidwrite(int c)写一个字符。
voidwrite(String str)写一个字符串。
voidwrite(String str,int off,int len)写一个字符串的一部分。
4-2、java.io.FileWriter【文件字符输出流】

​ FileWriter类继承了Writer类

4-2-1、常用构造器
构造器描述
FileWriter(File file)给File写一个FileWriter,使用平台的default charset
FileWriter(File file,boolean append)在给出的FileWriter下构造File,并使用平台的default charset构造一个布尔值,指示是否追加写入数据。
FileWriter(String fileName)构造一个FileWriter给出文件名,使用平台的default charset
FileWriter(String fileName,boolean append)使用平台的default charset构造一个FileWriter给定一个文件名和一个布尔值,指示是否追加写入数据。
4-2-2、常用方法与父类类同

5、字符输入流

5-1、java.io.Reader【字符的输入流】
5-1-1、常用方法
变量与类型方法描述
voidclose()关闭流并释放与其关联的所有系统资源。
intread()读一个字符。
intread(char[] cbuf)将字符读入数组。
abstract intread(char[] cbuf,int off,int len)将字符读入数组的一部分。
5-2、java.io.FileReader【文件字符输入流】
5-2-1、常用构造器
构造器描述
FileReader(File file)使用平台FileReader,在File读取时创建一个新的FileReader。
FileReader(String fileName)使用平台default charset创建一个新的FileReader,给定要读取的文件的名称。
5-2-2、常用方法与父类类同

6、flush刷新管道

​ 刷新:将内存中缓存的数据强制写入硬盘(上的各类文件)。【内存 ----》硬盘(或 输入方 ----》接收方)】

7、字节转换字符流

​ 转换流的作用:将字节流 “装饰” 为字符流(使用了装饰者设计模式)。

对应关系:①+②

① 字节输入流 ----》 字符输入流

FileInputStream fis = new FileInputStream("C:\\a.txt");
//对转换的字节流fis进行UTF-8编码,并转成字符流赋给isr
InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
while(true){
       int c = isr.read();
       if(c == -1){
           break;
       }
       System.out.print((char)c);	//输出a.txt文件中的所以字符
}
isr.close();	//关闭流

② 字节输出流 ----》 字符输出流

FileOutputStream fos = new FileOutputStream("C:\\a.txt");
//将字节输出流转换成字符输出流。
OutputStreamWriter osw = new OutputStreamWriter(fos);
osw.write("Hello World~");	//向a.txt写入“Hello World~”
osw.append("Hello->").append("Hello.");	//向a.txt追写
osw.close();	//关闭流

8、打印流与缓存读取流

8-1、打印流(PrintStream)
//字符输出(打印流)
PrintStream ps = new PrintStream("C:\\a.txt");
ps.println("Hello");	//向a.txt打印输出一段“Hello”字符串,并换行
p2.print("World.");		//向a.txt打印输出一段“World.”字符串,不换行

//字节输出(打印流)【与字符输出打印流类似,不同的是必须关闭或刷新,才能写入文件】
PrintWriter pw = new PrintWriter("D:\\a.txt");
pw.println("Hello world");
pw.close();//或者pw.flush();
8-2、缓存读取流(BufferedReader)
Reader r = new Reader("C:\\a.txt");
//将字符输入流 转换为带有缓存的(可一次读取一行的)缓存字符读取流
BufferedReader br = new BufferedReader(r);
String text;
//以行的方式【优点】读取a.txt,并打印输出显示,若为null表示读取完毕!
while((text = br.readLine()) != null){
       System.out.println(text);
}
br.close();	//注意:用完还得关闭(这是一种正确的操作方式)。
/**
 * 相对应的有 缓存输出流:BufferedWriter,但没有以行的方式写出的方法。
 */

9、收集异常日志

public static void main(String[] args) throws FileNotFoundException {
       try{
           String s = null;
           s.toString();	//将产生空指针异常
       }catch (NullPointerException n){
           DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
           PrintWriter pw = new PrintWriter("C:\\bug.txt");
           pw.println("时间:" + df.format(new Date()));	//将异常产生的时间放置bug.txt
           n.printStackTrace(pw);	//将异常信息打印至bug.txt
           pw.close();	//关闭流
       }
}

示例:

时间:2021-05-17 17:00:40
java.lang.NullPointerException
	at com.java.thecorelibrary._3_IO._7_CollectionExceptionLog.main(_7_CollectionExceptionLog.java:4)

10、java.util.Properties

​ Properties类既属于IO,又属于集合(因继承了Hashtable类,属于Map集合【双值存储】)

10-1、常用方法
变量和类型方法描述
synchronized Objectput(Object key,Object value)将指定的值与此映射中的指定的简相关联。
voidstore(OutputStream out, String comments)Properties表中的此属性列表(键和元素对)以适合使用 load(InputStream)方法加载到 Properties表的格式写入输出流。
voidstore(Writer writer, String comments)将此 Properties表中的此属性列表(键和元素对)以适合使用 load(Reader)方法的格式写入输出字符流。
StringgetProperty(String key)搜索指定键的属性。
Objectget(Object key)搜索指定键的属性。
voidload(InputStream inStream)从输入字节流中读取属性列表(键和元素对)。
voidload(Reader reader)以简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。

.properties文件(配置文件) 和 Properties类

​ .properties文件存储的是<键和值>;

​ Properties类操作的是<键,值>。

public static void main(String[] args) throws IOException {
        //字符输出流(写出去)
        Writer w = new FileWriter("src/com/java/thecorelibrary/_3_IO/Book.properties");
        Properties ppt = new Properties();
        //调用put()方法向Properties集合中放置(类添加)<Key,value>
        ppt.put("name","Java程序设计基础");
        ppt.put("info","讲述了Java这门语言");
        //将Properties集合中所有<Key,value> 存储至 Book.properties文件中(注释处于文件中的首行)
        ppt.store(w,"注释:技术类图书");
        w.close();  //正常关闭流

        //字符输入流(读进来)
        Reader r = new FileReader("src/com/java/thecorelibrary/_3_IO/Book.properties");
        //将Book.properties文件中的<Key,value> 加载至 Properties集合
        ppt.load(r);
//        System.out.println(ppt.getProperty("name"));    //通过键“name” 获取值“Java程序设计基础”
//        System.out.println(ppt.get("info"));    //通过键“info” 获取值“讲述了Java这门语言”
        Set s = ppt.keySet();   //将已加载至Properties集合中所有的键 变成 Set集合。
        //增强for循环遍历Set集合
        for (Object o : s) {
            System.out.println(o + " -> " + ppt.get(o)); //间接遍历Book.properties文件中所有的<Key,value>
        }

        System.out.println("---------------------------");

        //借助entrySet()方法将Properties集合 变成 Set集合。
        Set<Map.Entry<Object,Object>> es = ppt.entrySet();
        //借助iterator()方法将Set集合变成Iterator接口的对象(目的:迭代输出此接口中的值)
        Iterator iterator = es.iterator();
        //借助Iterator接口中的方法,间接迭代遍历由Properties集合变成的Set集合(Book.properties文件中的<Key=value>)
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        r.close();  //正常关闭流
    }

11、序列化技术【不当重点】

11-1、序列化

序列化:将程序中的对象(以字符序列的形式)存储在文件中。【保存对象】

注意:若自定义类的对象要被序列化,必须加标记接口(即实现Serilizable接后)才能实现序列化。

​ 即便是此类中成员属性有其他自定义类的对象,也必须加标记接口才能实现序列化。

public class Demo{
       public static void main(String[] args){
           Person p = new Person("Tom",21,"某某地方");
           Book b = new Book("Java程序设计基础","讲述了Java这门语言",p);//借书
           //序列化部分
           OutputStream os = new OutputStream("C:\\Object.txt");
           ObjectOutputStream oos = new ObjectOutputStream(os);	//输出流 -》 对象输出流
           oos.writeObject(b);	//写对象(将对象b写入Object.txt文件中)
           oos.close();
           //反序列化部分(代码位于以下反序列化中)
       }
       static class Person implements Serializable{
           private String name;
           private int age;
           private String add;
           //... ...
       }
       static class Book implements Serializable{
           private String name;
           private String info;
           private Person user;
           //... ...
       }
}
11-2、反序列化

反序列化:;将文件(中的字符序列)变成对象。【还原对象】

	InputStream is = new FileInputStream("C:\\Object.txt");
       ObjectInputStream ois = new ObjectInputStream(is);	//输入流 -》 对象输入流
       Book b2 = (Book) ois.readObject();	//读取对象强转为(Book类)赋给b2
       System.out.println(b2);	//打印对象(b2的toString())
       ois.close();

总结:序列化用于将程序中的对象保存下来;反序列化用于把已保存的对象还原至程序运行。

优点:① 保证JVM运行过程中断电后,对象数据在文件中任然存在,后期启动程序可加载其中继续运行。

​ ② 序列化成字节流形式的对象可进行网络传输(二进制形式),方便了网络传输。

​ ③ 通过序列化可以在进程间传递对象。

缺点:据了解序列化技术任然存在着bug,所以能少用就尽量不用,往后有可能会被替代。

11-3、try-with-resources

​ try-with-resources:即属于IO,也属于异常处理。

​ 作用:①操作需要关闭的资源。②异常处理。

//JDK1.7之前,处理异常和关闭资源的方式(try-catch-finally):

FileReader fr = null;
try{
       fr = new FileReader("C:\\1.txt");
       int c = fr.read();
       System.out.println((char)c);
}catch(IoException e){
       e.printStackTrace();
}finally{
       try{
           fr.close();
       }catch(Exception e){
           e.printStackTrace();
       }
}
//为了读取一个字符,需要释放资源并处理异常(采用以上方式显然比较麻烦)

//JDK1.7时,处理异常和关闭资源的方式(try-with-resources):

try(FileInputStream fis = new FileInputStream("C:\\2.txt")){
       int c = fis.read();
       System.out.println((char)c);
}catch(IOException e){
       e.printStackTrace();
}//此finally自动被执行(省略不写)
//若要在try-catch之后仍能使用,采用以上方式则不行。JDK9则解决了这一不足之处。

//JDK9时,处理异常和关闭资源的方式(try-with-resources):

​ 与JDK1.7不同的是,实现了多个对象的异常处理和资源释放的功能,多个对象名在try中以";"分隔。

//用法①:
try(FileReader fr1 = new FileReader("C:\\1.txt");
    FileReader fr2 = new FileReader("C:\\2.txt");
    FileReader fr3 = new FileReader("D:\\bug.txt";
    Person p = new Person("Tom",'男',21))){
       int c;
       while((c = fr1.read()) != -1){
           System.out.print((char)c);	//读取1.txt
       }
       while((c = fr2.read()) != -1){
           System.out.print((char)c);	//读取2.txt
       }
       while((c = fr3.read()) != -1){
           System.out.print((char)c);	//读取bug.txt
       }
       System.out.println(p);
}catch(IOException e){
       e.printStackTrace();
}//此finally自动被执行(省略不写)
//用法②:
FileReader fr1 = new FileReader("C:\\1.txt");
FileReader fr2 = new FileReader("C:\\2.txt");
FileReader fr3 = new FileReader("D:\\bug.txt";
Person p = new Person("Tom",'男',21);
try(fr1;fr2;fr3;p){
       int c;
       while((c = fr1.read()) != -1){
           System.out.print((char)c);	//读取1.txt
       }
       while((c = fr2.read()) != -1){
           System.out.print((char)c);	//读取2.txt
       }
       while((c = fr3.read()) != -1){
           System.out.print((char)c);	//读取bug.txt
       }
       System.out.println(p);
}catch(IOException e){
       e.printStackTrace();
}//此finally自动被执行(省略不写)
int fr1HashValue = fr1.hashCode();	//保证了任可以操作对象,是JDK9之前未有的实现方式。
//若要能在try()内创建类的对象需要实现Closeable接口(或AutoCloseable接口)并重写close()方法。
public class Person implements Closeable{
       private String name;
       private char sex;
       private int age;
    
       public Person(){
       }
    
       public Person(String name,char sex,int age){
           this.name = name;
           this.sex = sex;
           this.age = age;
       }
    
       //... ...
    
       @Override//释放资源自动执行finally调用此方法
       public void close() throws IOException {
       }
}

总结:① 若要实现多个对象的异常处理和资源释放,使用JDK9版本中的try-with-resources。

​ ② 多个对象将在try()中以“;”分隔,例如:try(对象名1;对象名2;… …){}catch(){}

注意:实现自定义类的对象的资源释放,必须实现Closeable接口(或AutoCloseable接口)并重写close()方法。

11-4、Serializable接口实现序列化和反序列化

​ 11-1 中有所描述。

11-5、部分属性的序列化和反序列化

实现部分字段序列化的方式:

  • 使用transient修饰符。
  • 使用static修饰符。
  • 默认方法writerObject和readObject。

示例代码如下

/*序列化与反序列化*/
package com.java.serialization;

import java.io.*;

public class MySerialization {
    /**
     * 序列化对象
     * @param obj
     * @param fileName
     * @throws IOException
     */
    public static void serialization(Object obj,String fileName) throws IOException {
        OutputStream os = new FileOutputStream(fileName);
        ObjectOutputStream oos = new ObjectOutputStream(os);
        oos.writeObject(obj);
        oos.close();
    }

    /**
     * 反序列化对象
     * @param fileName
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static Object deSerialization(String fileName) throws IOException, ClassNotFoundException {
        InputStream is = new FileInputStream(fileName);
        ObjectInputStream ois = new ObjectInputStream(is);
        Object o = ois.readObject();
        ois.close();
        return o;
    }
}
/*Main类*/
package com.java.test;

import com.java.pojo.Student;
import com.java.serialization.MySerialization;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class Main{
    public static void main(String[] args){
        List<Student> all = new ArrayList<>();
        all.add(new Student("Tom",'男',23,123123,1008611));
        all.add(new Student("Jerry",'男',21,456456,100101));
        
        try{
            //序列化对象all
            MySerialization.serialization(all,"C:\\Object1.txt");
            System.out.println("序列前原始对象:");
            //两个输出一样的学号和姓名,是因为它们是静态成员变量(内存中只能存在一个公共的变量),会随对象s2初始化所更改。
            System.out.println(all.get(0));
            System.out.println(all.get(1));

            s1.setName("无名称");  //因name属于静态成员变量

            //反序列化
            List<Student> all1 = (List<Student>)MySerialization.deSerialization("C:\\Object1.txt");
            System.out.println("反序列化之后的对象:");
            //同理。
            System.out.println(all1.get(0));
            System.out.println(all1.get(1));
        }catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
//结果:
序列前原始对象:
姓名:Tom,性别:女,年龄:23,QQ:123123,电话:1008611
姓名:Jerry,性别:女,年龄:21,QQ:456456,电话:100101
反序列化之后的对象:
姓名:null,性别:男,年龄:0,QQ:123123,电话:1008611
姓名:null,性别:男,年龄:0,QQ:456456,电话:100101
/*Student类*/
package com.java.pojo;

import java.io.*;

public class Student implements Serializable {
    //被transient修饰的不参与序列化
    private transient String name;	//姓名
    //被static修饰的也不参与序列化
    private static char sex;		//性别
    private int age;				//年龄
    private int qq;					//QQ
    private int tel;				//电话
    
    public Student(){
    }
    
    public Student(String name,char sex,int age,int qq,int tel) {
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.qq = qq;
        this.tel = tel;
    }
    
    //实现指定成员属性的序列化(qq,tel)
    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
		out.writeObject(qq);
        out.writeObject(tel);
    }
    //实现指定成员属性的反序列化(qq,tel)
    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
		qq = (int)in.readObject();
        tel = (int)in.readObject();
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public char getSex() {
        return sex;
    }
    
    public void setSex(char sex) {
        this.sex = sex;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    public int getQq() {
        return qq;
    }
    
    public void setQq(int qq) {
        this.qq = qq;
    }
    
    public int getTel() {
        return tel;
    }
    
    public void setTel(int tel) {
        this.tel = tel;
    }
    
    @Override
    public String toString() {
        return "姓名:" + name + ",性别:" + sex + ",年龄:" + age + ",QQ:" + qq + ",电话:" + tel;
    }
}
11-6、Externalizable接口实现序列化和反序列化

通过实现Externalizable接口,重写writeExternal()和readExternal()方法来实现。

//部分示例:
public class Student implements Externalizable {
        //被transient修饰的不参与序列化
        private transient String name;	//姓名
        //被static修饰的也不参与序列化
        private static char sex;		//性别
        private int age;				//年龄
        private int qq;					//QQ
        private int tel;				//电话

        public Student(){
    }

    public Student(String name,char sex,int age,int qq,int tel) {
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.qq = qq;
        this.tel = tel;
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(qq);
        out.writeObject(tel);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        qq = (int) in.readObject();
        tel = (int) in.readObject();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getQq() {
        return qq;
    }

    public void setQq(int qq) {
        this.qq = qq;
    }

    public int getTel() {
        return tel;
    }

    public void setTel(int tel) {
        this.tel = tel;
    }

    @Override
    public String toString() {
        return "姓名:" + name + ",性别:" + sex + ",年龄:" + age + ",QQ:" + qq + ",电话:" + tel;
    }
}
11-7、Serializable VS Externalizable

实现序列化有两种接口:Serializable接口 和 Externalizable接口

区别SerializableExternalizable
实现复杂度实现简单,Java对其有内建支持实现复制,由开发人员自己完善
执行效率所有对象由Java统一保存,性能较低开发人员决定哪个对象保存,可能造成速度提升
保存信息保存时占用空间大部分存储,可能造成空间减少
使用频率偏低
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值