文章目录
I : in(输入,读取) O : out (输出,写出)
对于需要掌握的内容:
- 文件的增、删、改及查找等操作。
- 对文件字节上数据的读取和写出。
- 对文本文件字符上的读取和写出。
一、java.io.File
描述:文件或目录路径的抽象表示。
1、字段(与系统相关,便于跨平台)
变量和类型 | 字段 | 描述 |
---|---|---|
static String | pathSeparator | 与系统相关的路径分隔符,以字符串形式体现。 |
static char | pathSeparatorChar | 与系统相关的路径分隔符,以字符形式体现。 |
static String | separator | 系统相关的默认名称分隔符,以字符串形式体现。 |
static char | separatorChar | 系统相关的默认名称分隔符,以字符形式体现。 |
eg:File.separator; //在UNIX系统上是’/’,而在Windows系统上是’\\’。(区别)
2、构造方法
构造器 | 描述 |
---|---|
File(String pathname) | 通过将给定的路径名字符串转为抽象路径名来创建新的File实例。 |
File(File parent , String child) | 从父抽象路径名和子路径名字符串创建新的File实例。 |
File(String parent , String child) | 从父路径名字符串和子路径名字符串创建新的File实例。 |
3、成员方法
常用方法:
变量和类型 | 方法 | 描述 |
---|---|---|
boolean | exists() | 测试此抽象路径名表示的文件或目录是否存在。【创建文件前建议先使用exists()方法判断】 |
boolean | createNewFile() | 仅当此名称文件不存在时,创建由此抽象路径命名的新空文件。 |
boolean | mkdir() | 创建此抽象路径名指定的一级目录(即一个文件夹)。 |
boolean | mkdirs() | 创建此抽象路径名指定的一级或多层目录(即一个或多层文件夹)。 |
boolean | delete() | 删除此抽象路径名表示的文件或目录。 |
void | deleteOnExit() | 请求在JVM终止时删除此抽象路径表示的文件或目录。 |
boolean | renameTo(File dest) | 重命名此抽象路径名表示的文件。【兼重命名+剪切功能】 |
long | length() | 返回此抽象路径名表示的文件的长度。【单位:字节(byte)】 |
String[] | list() | 返回一个字符串数组,用于命名此抽象路径名表示的目录中的文件或目录。 |
String[] | list(FilenameFilter filter) | 返回一个字符串数组,用于命名此抽象路径名表示的目录中的文件或目录,以满足指定的过滤器。 |
File[] | listFile() | 返回一个抽象路径名数组,表示此抽象路径名表示的目录中的文件或目录。 |
File[] | listFile(FilenameFilter filter) | 返回一个抽象路径名数组,表示此抽象路径名表示的目录中满足过滤器的文件或目录。 |
File | getAbsoluteFile() | 返回此抽象路径名的绝对形式。 |
String | getAbsolutePath() | 返回此抽象路径名的绝对路径名字符串。(常用) |
File | getCanonicalFile() | 返回此抽象路径名的规范形式。 |
String | getCanonicalPath() | 返回此抽象路径名的规范路径名字符串。 |
String | getName() | 返回此抽象路径名表示的文件或目录的名称。 |
String | getParent() | 返回此抽象路径名父项的路径名字符串,若此路径未指定父目录,则返回null。 |
File | getParentFile() | 返回此抽象路径名父项的抽象路径名,若此路径未指定父目录,则返回null。 |
String | getPath() | 将此抽象路径转为路径名字符串。 |
boolean | isAbsolute() | 测试此抽象路径名是否为绝对路径。 |
boolean | isDirectory() | 测试此抽象路径名表示的文件是否为目录(即文件夹)。 |
boolean | isFile() | 测试此抽象路径名指定的文件是否为普通文件。 |
其他方法:
变量和类型 | 方法 | 描述 |
---|---|---|
boolean | canExecute() | 测试应用程序是否可以(执行)此抽象路径名表示的文件。 |
boolean | canRead() | 测试应用程序是否可以(读取)此抽象路径名表示的文件。 |
boolean | canWrite() | 测试应用程序是否可以(修改)此抽象路径名表示的文件。 |
int | compareTo(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、常用方法
变量和类型 | 方法 | 描述 |
---|---|---|
void | close() | 关闭此输出流并释放与此流关联的所有系统资源。【重点】 |
void | flush() | 刷新此输出流并强制写出任何缓冲的输出字节。 |
void | write(byte[] b) | 将b.length字节从指定的字节数组写入此输出流。 |
void | write(byte[] b,int off,int len) | 将从偏移量off开始的指定字节数组中的len字节写入此输出流。 |
abstract void | write(int b) | 将指定的字节写此输出流。 |
1-1-2、其他方法
变量与类型 | 方法 | 描述 |
---|---|---|
static OutputStream | nullOutputStream() | 返回一个新的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、常用方法
变量和类型 | 方法 | 描述 |
---|---|---|
void | close() | 关闭此输入流并释放与该流关联的所有系统资源。【重点】 |
abstract int | read() | 从输入流中读取下一个数据字节。 |
int | read(byte[] b) | 从输入流中读取一组数据字节并将它们存储到缓冲区数组b。【特常用】 |
2-1-2、其他方法
变量和类型 | 方法 | 描述 |
---|---|---|
int | read(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个字节时,需要8个二进制位对其进行编码;
- 当需要2个字节时,需要16个二进制位对其进行编码;
- 当需要3个字节时,需要24个二进制位对其进行编码;
- 当需要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、常用方法
变量和类型 | 方法 | 描述 |
---|---|---|
Writer | append(char c) | 将指定的字符追加到此writer。 |
abstract void | close() | 关闭流。 |
abstract void | flush() | 刷新流。 |
void | write(char[] cbuf) | 写一个字符数组。 |
void | write(char[] cbuf,int off,int len) | 写一个字符数组的一部分。 |
void | write(int c) | 写一个字符。 |
void | write(String str) | 写一个字符串。 |
void | write(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、常用方法
变量与类型 | 方法 | 描述 |
---|---|---|
void | close() | 关闭流并释放与其关联的所有系统资源。 |
int | read() | 读一个字符。 |
int | read(char[] cbuf) | 将字符读入数组。 |
abstract int | read(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 Object | put(Object key,Object value) | 将指定的值与此映射中的指定的简相关联。 |
void | store(OutputStream out, String comments) | Properties表中的此属性列表(键和元素对)以适合使用 load(InputStream)方法加载到 Properties表的格式写入输出流。 |
void | store(Writer writer, String comments) | 将此 Properties表中的此属性列表(键和元素对)以适合使用 load(Reader)方法的格式写入输出字符流。 |
String | getProperty(String key) | 搜索指定键的属性。 |
Object | get(Object key) | 搜索指定键的属性。 |
void | load(InputStream inStream) | 从输入字节流中读取属性列表(键和元素对)。 |
void | load(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接口
区别 | Serializable | Externalizable |
---|---|---|
实现复杂度 | 实现简单,Java对其有内建支持 | 实现复制,由开发人员自己完善 |
执行效率 | 所有对象由Java统一保存,性能较低 | 开发人员决定哪个对象保存,可能造成速度提升 |
保存信息 | 保存时占用空间大 | 部分存储,可能造成空间减少 |
使用频率 | 高 | 偏低 |