序列化、打印流、压缩流、工具包
1. 序列化
1.1 概述
Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据
、对象的类型
和对象中存储的属性
等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。
反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。对象的数据
、对象的类型
和对象中存储的数据
信息,都可以用来在内存中创建对象。看图理解序列化:
1.2 ObjectOutputStream类
java.io.ObjectOutputStream
类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。
构造方法
public ObjectOutputStream(OutputStream out)
: 创建一个指定OutputStream的ObjectOutputStream。
构造举例,代码如下:
FileOutputStream fileOut = new FileOutputStream("employee.txt");ObjectOutputStream out = new ObjectOutputStream(fileOut);
序列化操作
- 一个对象要想序列化,必须满足两个条件:
- 该类必须实现
java.io.Serializable
接口,Serializable
是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException
。 - 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用
transient
关键字修饰。
public class Employee implements java.io.Serializable { public String name; public String address; public transient int age; // transient瞬态修饰成员,不会被序列化 public void addressCheck() { System.out.println("Address check : " + name + " -- " + address); }}
写出对象方法
public final void writeObject (Object obj)
: 将指定的对象写出。
public class SerializeDemo{ public static void main(String [] args) { Employee e = new Employee(); e.name = "zhangsan"; e.address = "beiqinglu"; e.age = 20; try { // 创建序列化流对象 ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("employee.txt")); // 写出对象 out.writeObject(e); // 释放资源 out.close(); fileOut.close(); System.out.println("Serialized data is saved"); // 姓名,地址被序列化,年龄没有被序列化。 } catch(IOException i) { i.printStackTrace(); } }}输出结果:Serialized data is saved
1.3 ObjectInputStream类
ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。
构造方法
public ObjectInputStream(InputStream in)
: 创建一个指定InputStream的ObjectInputStream。
反序列化操作1
如果能找到一个对象的class文件,我们可以进行反序列化操作,调用ObjectInputStream
读取对象的方法:
public final Object readObject ()
: 读取一个对象。
public class DeserializeDemo { public static void main(String [] args) { Employee e = null; try { // 创建反序列化流 FileInputStream fileIn = new FileInputStream("employee.txt"); ObjectInputStream in = new ObjectInputStream(fileIn); // 读取一个对象 e = (Employee) in.readObject(); // 释放资源 in.close(); fileIn.close(); }catch(IOException i) { // 捕获其他异常 i.printStackTrace(); return; }catch(ClassNotFoundException c) { // 捕获类找不到异常 System.out.println("Employee class not found"); c.printStackTrace(); return; } // 无异常,直接打印输出 System.out.println("Name: " + e.name);// zhangsan System.out.println("Address: " + e.address); // beiqinglu System.out.println("age: " + e.age); // 0 }}
对于JVM可以反序列化对象,它必须是能够找到class文件的类。如果找不到该类的class文件,则抛出一个 ClassNotFoundException
异常。
反序列化操作2
另外,当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException
异常。发生这个异常的原因如下:
- 该类的序列版本号与从流中读取的类描述符的版本号不匹配
- 该类包含未知数据类型
- 该类没有可访问的无参数构造方法
Serializable
接口给需要序列化的类,提供了一个序列版本号。serialVersionUID
该版本号的目的在于验证序列化的对象和对应类是否版本匹配。
public class Employee implements java.io.Serializable { // 加入序列版本号 private static final long serialVersionUID = 1L; public String name; public String address; // 添加新的属性 ,重新编译, 可以反序列化,该属性赋为默认值. public int eid; public void addressCheck() { System.out.println("Address check : " + name + " -- " + address); }}
1.4 练习:序列化集合
- 将存有多个自定义对象的集合序列化操作,保存到
list.txt
文件中。 - 反序列化
list.txt
,并遍历集合,打印对象信息。
案例分析
- 把若干学生对象 ,保存到集合中。
- 把集合序列化。
- 反序列化读取时,只需要读取一次,转换为集合类型。
- 遍历集合,可以打印所有的学生信息
案例实现
public class SerTest {public static void main(String[] args) throws Exception {// 创建 学生对象Student student = new Student("老王", "laow");Student student2 = new Student("老张", "laoz");Student student3 = new Student("老李", "laol");ArrayList<Student> arrayList = new ArrayList<>();arrayList.add(student);arrayList.add(student2);arrayList.add(student3);// 序列化操作// serializ(arrayList);// 反序列化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("list.txt"));// 读取对象,强转为ArrayList类型ArrayList<Student> list = (ArrayList<Student>)ois.readObject(); for (int i = 0; i < list.size(); i++ ){ Student s = list.get(i); System.out.println(s.getName()+"--"+ s.getPwd()); }}private static void serializ(ArrayList<Student> arrayList) throws Exception {// 创建 序列化流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("list.txt"));// 写出对象oos.writeObject(arrayList);// 释放资源oos.close();}}
2. 打印流
2.1 概述
平时我们在控制台打印输出,是调用print
方法和println
方法完成的,这两个方法都来自于java.io.PrintStream
类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方式。
2.2 PrintStream类
构造方法
public PrintStream(String fileName)
: 使用指定的文件名创建一个新的打印流。
构造举例,代码如下:
PrintStream ps = new PrintStream("ps.txt");
改变打印流向
System.out
就是PrintStream
类型的,只不过它的流向是系统规定的,打印在控制台上。不过,既然是流对象,我们就可以玩一个"小把戏",改变它的流向。
public class PrintDemo { public static void main(String[] args) throws IOException {// 调用系统的打印流,控制台直接输出97 System.out.println(97); // 创建打印流,指定文件的名称 PrintStream ps = new PrintStream("ps.txt"); // 设置系统的打印流流向,输出到ps.txt System.setOut(ps); // 调用系统的打印流,ps.txt中输出97 System.out.println(97); }}
3. 压缩流和解压缩流
压缩流:
负责压缩文件或者文件夹
解压缩流:
负责把压缩包中的文件和文件夹解压出来
public class ZipStreamDemo1 { public static void main(String[] args) throws IOException { //1.创建一个File表示要解压的压缩包 File src = new File("D:\\aaa.zip"); //2.创建一个File表示解压的目的地 File dest = new File("D:\\"); //调用方法 unzip(src,dest); } //定义一个方法用来解压 public static void unzip(File src,File dest) throws IOException { //解压的本质:把压缩包里面的每一个文件或者文件夹读取出来,按照层级拷贝到目的地当中 //创建一个解压缩流用来读取压缩包中的数据 ZipInputStream zip = new ZipInputStream(new FileInputStream(src)); //要先获取到压缩包里面的每一个zipentry对象 //表示当前在压缩包中获取到的文件或者文件夹 ZipEntry entry; while((entry = zip.getNextEntry()) != null){ System.out.println(entry); if(entry.isDirectory()){ //文件夹:需要在目的地dest处创建一个同样的文件夹 File file = new File(dest,entry.toString()); file.mkdirs(); }else{ //文件:需要读取到压缩包中的文件,并把他存放到目的地dest文件夹中(按照层级目录进行存放) FileOutputStream fos = new FileOutputStream(new File(dest,entry.toString())); int b; while((b = zip.read()) != -1){ //写到目的地 fos.write(b); } fos.close(); //表示在压缩包中的一个文件处理完毕了。 zip.closeEntry(); } } zip.close(); }}
public class ZipStreamDemo2 { public static void main(String[] args) throws IOException { //1.创建File对象表示要压缩的文件 File src = new File("D:\\a.txt"); //2.创建File对象表示压缩包的位置 File dest = new File("D:\\"); //3.调用方法用来压缩 toZip(src,dest); } public static void toZip(File src,File dest) throws IOException { //1.创建压缩流关联压缩包 ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(dest,"a.zip"))); //2.创建ZipEntry对象,表示压缩包里面的每一个文件和文件夹 //参数:压缩包里面的路径 ZipEntry entry = new ZipEntry("aaa\\bbb\\a.txt"); //3.把ZipEntry对象放到压缩包当中 zos.putNextEntry(entry); //4.把src文件中的数据写到压缩包当中 FileInputStream fis = new FileInputStream(src); int b; while((b = fis.read()) != -1){ zos.write(b); } zos.closeEntry(); zos.close(); }}
public class ZipStreamDemo3 { public static void main(String[] args) throws IOException { //1.创建File对象表示要压缩的文件夹 File src = new File("D:\\aaa"); //2.创建File对象表示压缩包放在哪里(压缩包的父级路径) File destParent = src.getParentFile();//D:\\ //3.创建File对象表示压缩包的路径 File dest = new File(destParent,src.getName() + ".zip"); //4.创建压缩流关联压缩包 ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dest)); //5.获取src里面的每一个文件,变成ZipEntry对象,放入到压缩包当中 toZip(src,zos,src.getName());//aaa //6.释放资源 zos.close(); } public static void toZip(File src,ZipOutputStream zos,String name) throws IOException { //1.进入src文件夹 File[] files = src.listFiles(); //2.遍历数组 for (File file : files) { if(file.isFile()){ //3.判断-文件,变成ZipEntry对象,放入到压缩包当中 ZipEntry entry = new ZipEntry(name + "\\" + file.getName());//aaa\\no1\\a.txt zos.putNextEntry(entry); //读取文件中的数据,写到压缩包 FileInputStream fis = new FileInputStream(file); int b; while((b = fis.read()) != -1){ zos.write(b); } fis.close(); zos.closeEntry(); }else{ //4.判断-文件夹,递归 toZip(file,zos,name + "\\" + file.getName()); // no1 aaa \\ no1 } } }}
4. 工具包(Commons-io)
介绍:
Commons是apache开源基金组织提供的工具包,里面有很多帮助我们提高开发效率的API
比如:
StringUtils 字符串工具类
NumberUtils 数字工具类
ArrayUtils 数组工具类
RandomUtils 随机数工具类
DateUtils 日期工具类
StopWatch 秒表工具类
ClassUtils 反射工具类
SystemUtils 系统工具类
MapUtils 集合工具类
Beanutils bean工具类
Commons-io io的工具类
等等…
其中:Commons-io是apache开源基金组织提供的一组有关IO操作的开源工具包。
作用:提高IO流的开发效率。
使用方式:
1,新建lib文件夹
2,把第三方jar包粘贴到文件夹中
3,右键点击add as a library
代码示例:
public class CommonsIODemo1 { public static void main(String[] args) throws IOException { }}
5. 工具包(hutool)
介绍:
Commons是国人开发的开源工具包,里面有很多帮助我们提高开发效率的API
官网:
https://hutool.cn/
API文档:
https://apidoc.gitee.com/dromara/hutool/
中文使用文档:
https://hutool.cn/docs/#/
比如:
DateUtil 日期时间工具类
TimeInterval 计时器工具类
StrUtil 字符串工具类
HexUtil 16进制工具类
HashUtil Hash算法类
ObjectUtil 对象工具类
ReflectUtil 反射工具类
TypeUtil 泛型类型工具类
PageUtil 分页工具类
NumberUtil 数字工具类
使用方式:
1,新建lib文件夹
2,把第三方jar包粘贴到文件夹中
3,右键点击add as a library
代码示例:
public class Test1 { public static void main(String[] args) { List<String> list = FileUtil.readLines("D:\\a.txt", "UTF-8"); System.out.println(list); }}
后记
👉👉💕💕美好的一天,到此结束,下次继续努力!欲知后续,请看下回分解,写作不易,感谢大家的支持!! 🌹🌹🌹
来源地址:https://blog.csdn.net/m0_59230408/article/details/132334895