目录
序列化和反序列化是什么
当两个进程远程通信时,彼此可以发送各种类型的数据。 无论是何 种类型的数据,都会以二进制序列的形式在网络上传送。比如,我 们可以通过http协议发送字符串信息;我们也可以在网络上直接发 送Java对象。发送方需要把这个Java对象转换为字节序列,才能在 网络上传送;接收方则需要把字节序列再恢复为Java对象才能正常 读取。 把Java对象转换为字节序列的过程称为对象的序列化。把字节序列 恢复为Java对象的过程称为对象的反序列化。
序列化涉及的类和接口
ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写 到一个目标输出流中。
ObjectInputStream代表对象输入流,它的readObject()方法从一个 源输入流中读取字节序列,再把它们反序列化为一个对象,并将其 返回。 只有实现了Serializable接口的类的对象才能被序列化。 Serializable接口是一个空接口,只起到标记作用。
将对象序列化到文件
ObjectOutputStream可以将一个内存中的Java对象通过序列化的方 式写入到磁盘的文件中。被序列化的对象必须要实现Serializable序 列化接口,否则会抛出异常。
创建对象
- public class Users implements Serializable {
- private int userid;
- private String username;
- private String userage;
- public Users(int userid, String username, String userage) {
- this.userid = userid;
- this.username = username;
- this.userage = userage;
- }
- public Users() { }
- public int getUserid() {
- return userid;
- }
- public void setUserid(int userid) {
- this.userid = userid;
- }
- public String getUsername() {
- return username;
- }
- public void setUsername(String username)
- {
- this.username = username;
- }
- public String getUserage() {
- return userage;
- }
- public void setUserage(String userage) {
- this.userage = userage;
- }
- @Override
- public String toString() {
- return "Users{" +
- "userid=" + userid +
- ", username='" + username + '\'' +
- ", userage='" + userage + '\'' +
- '}';
- }
序列化对象
- public class TestObjectOutputStream {
- public static void main(String[] args) {
- //创建对象输出字节流与文件输出字节流对象
- try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/data3"))){
- //创建Users对象
- Users users = new Users(1,"Oldlu","18");
- //将对象序列化到文件中
- oos.writeObject(users);
- //刷新
- oos.flush();
- }catch(IOException e){
- e.printStackTrace();
- }
- }
- }
- public class TestObjectInputStream {
- public static void main(String[] args) {
- //创建对象输入字节流与文件字节输入流对象
- try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/data3")))
- {
- //将对象反序列化到内存中
- Users users = (Users) ois.readObject();
- System.out.println(users);
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- }
当以文件作为数据源或目标时,除了可以使用字符串作为文件以及 位置的指定以外,我们也可以使用File类指定。
- public class TestFile {
- public static void main(String[] args) {
- //创建字符缓冲流与文件字符输入流对象
- try(BufferedReader br = new BufferedReader(new FileReader(new File("d:/sxt.txt")));
- //创建字符输出流对象
- PrintWriter pw = new PrintWriter(new File("d:/sxt8.txt"))){
- //操作流
- String temp = "";
- int i=1;
- while((temp = br.readLine()) != null){
- pw.println(i+","+temp);
- i++;
- }
- pw.flush();
- }catch(IOException e){
- e.printStackTrace();
- }
- }
- }
装饰器模式简介
装饰器模式是GOF23种设计模式中较为常用的一种模式。它可以实 现对原有类的包装和装饰,使新的类具有更强的功能。
装饰器模式
- class Iphone {
- private String name;
- public Iphone(String name) {
- this.name = name;
- }
- public void show() {
- System.out.println("我是" + name + ",可以在屏幕上显示");
- }
- }
- class TouyingPhone {
- public Iphone phone;
- public TouyingPhone(Iphone p) {
- this.phone = p;
- }
- // 功能更强的方法
- public void show() {
- phone.show();
- System.out.println("还可以投影,在墙壁上显示");
- }
- }
- public class TestDecoration {
- public static void main(String[] args) {
- Iphone phone = new Iphone("iphone30");
- phone.show();
- System.out.println("===============装饰后");
- TouyingPhone typhone = newTouyingPhone(phone);
- typhone.show();
- }
- }
IO流体系中的装饰器模式
IO流体系中大量使用了装饰器模式,让流具有更强的功能、更强的 灵活性。比如:
- FileInputStream fis = new FileInputStream(src);
- BufferedInputStream bis = new BufferedInputStream(fis);
显然BufferedInputStream装饰了原有的FileInputStream,让普通 的FileInputStream也具备了缓存功能,提高了效率。
Apache基金会介绍
Apache软件基金会(也就是Apache Software Foundation,简称 为ASF),是专门为支持开源软件项目而办的一个非盈利性组织。 在它所支持的Apache项目与子项目中,所发行的软件产品都遵循 Apache许可证(Apache License)。 官方网址为: www.apache.org 。 很多著名的Java开源项目都来源于这个组织。比如:commons、 kafka、lucene、maven、shiro、struts等技术,以及大数据技术 中的:hadoop(大数据第一技术)、hbase、spark、storm、 mahout等。
commons-io工具包
Apache的commons-io工具包中提供了IOUtils/FileUtils,为我们 提供了更加简单、功能更加强大的文件操作和IO流操作功能。非常 值得大家学习和使用。
下载与添加commons-io包
下载地址 https://commons.apache.org/proper/commons-io/download_i o.cgi
添加jar包
FileUtils类中常用方法的介绍
打开FileUtils的api文档,我们抽出一些工作中比较常用的方法,进 行总结和讲解。总结如下:
读取文件内容,并输出到控制台上(只需一行代码!)
- import java.io.File;
- import org.apache.commons.io.FileUtils;
- public class TestUtils1 {
- public static void main(String[] args) throws Exception {
- String content = FileUtils.readFileToString(new File("d:/a.txt"), "gbk");
- System.out.println(content);
- }
- }
使用FileUtils工具类实现目录拷贝
我们可以使用FileUtils完成目录拷贝,在拷贝过程中可以通过文件过 滤器(FileFilter)选择拷贝内容。
- import java.io.File;
- import java.io.FileFilter;
- import org.apache.commons.io.FileUtils;
- public class TestFileUtilsDemo2 {
- public static void main(String[] args) throws Exception {
- FileUtils.copyDirectory(new File("d:/aaa"), new File("d:/bbb"), new FileFilter() {
- @Override
- public boolean accept(File pathname) {// 使用FileFilter过滤目录和以html结尾的文件
- if (pathname.isDirectory() || pathname.getName().endsWith("html")) {
- return true;
- } else {
- return false;
- }
- }
- });
- }
- }
IOUtils的妙用
打开IOUtils的api文档,我们发现它的方法大部分都是重载的。所 以,我们理解它的方法并不是难事。因此,对于方法的用法总结如 下:
我们没有必要对每个方法做测试,只是演示一下读入d:/sxt.txt文件 内容到程序中,并转成String对象,打印出来。
IOUtils的使用
- import java.io.*;
- import org.apache.commons.io.IOUtils;
- public class TestIOUtilsDemo {
- public static void main(String[] args) throws Exception {
- String content = IOUtils.toString(new FileInputStream("d:/sxt.txt"),"utf-8");
- System.out.println(content);
- }
- }
本章总结
按流的方向分类:
输入流:数据源到程序(InputStream、Reader读进来)。
输出流:程序到目的地(OutputStream、Writer写出去)。
按流的处理数据单元分类:
字节流:按照字节读取数据(InputStream、 OutputStream)。
字符流:按照字符读取数据(Reader、Writer)。
按流的功能分类:
节点流:可以直接从数据源或目的地读写数据。
处理流:不直接连接到数据源或目的地,是处理流的流。通 过对其他流的处理提高程序的性能。
IO的四个基本抽象类:InputStream、OutputStream、 Reader、Writer
InputStream的实现类:
FileInputStream
BufferedInputStream
DataInputStream
ObjectInputStream
OutputStream的实现类:
FileOutputStream
BufferedOutputStream
DataOutputStream
ObjectOutputStream
Reader的实现类
FileReader
BufferedReader
InputStreamReader
Writer的实现类
FileWriter
BufferedWriter
OutputStreamWriter
PrintWriter
把Java对象转换为字节序列的过程称为对象的序列化。
把字节序列恢复为Java对象的过程称为对象的反序列化。