目录
13.1serializable序列化
一、serializable序列化
序列化(serialization)指将一个java Object实例写入一个字节流的过程,序列化对象可以将其状态存储成文件,这一过程又被称作对象的持久化,可以将序列化后的对象进行网络传输,总之,序列化是个有趣的过程。既然存在序列化,就有反序列化,反序列化是字节流将会被正确地恢复成Object对象。
在java中序列化是通过实现接口java.io.Serializable,Serializable接口是一个标记性接口,它告诉JVM将实现他的对象转换成一系列二进制字节,并可在以后完全恢复回原来的样子,而且这个接口没有任何方法和属性,这种被称作“空接口”。“空接口”只用来标明一个类需要被序列化,剩下的工作交给jvm。实现Serializable接口的类的实例对象可以被序列化或反序列化。实现Serializable接口同样会传递到子类,即父类序列化则子类必然序列化。在序列化是需要注意,可以使用transient关键字声明一个属性不需要序列化。使用static关键字声明的静态的属性也被排除在序列化之外。除了Serializable外,还可以使用Externalizable接口和ObjectOutput接口支持对象序列化。
二、对象流ObjectInputStream和ObjectOutputStream
Serializable只是标明一个对象可以被序列化,而真正需要序列化时可以把任务交给对象流ObjectOutputStream去完成,其中的writeObject( )方法用作序列化对象,序列化后的流数据通过被ObjectOutputStream修饰的OutputStream输出到文件、网路或其他地方。
创建ObjectOutputStream的两个构造器:
protected ObjectOutputStream()
该构造器是受保护的,目的是为重新实现 ObjectOutputStream 的子类提供一种途径,让它不必分配仅ObjectOutputStream 的实现使用的私有数据。
ObjectOutputStream(OutputStream out)
指定负责输出的字节流OutputStream,ObjectOutputStream修饰OutputStream提供更为“高级”的序列化功能。
ObjectOutputStream也是一个需要被装饰使用的流,我们可以使用一个网络流来在网络上传递对象或者用一个文件输出流来把对象保存到文件,其writeObject()可以被对象写入流。ObjectInputStream是对象输入流,它的readObject()方法完成ObjectOutputStream的可逆操作。
三、序列化的作用
序列化的对象方便与传输或者是保存到文件(对象的持久化)。
1、方便网络传输。尤其是在套接字中传输对象时使用。
2、可以持久化保存对象的状态(各个属性值)。
3、屏蔽了操作系统的差异。比如在Windows机器上创建一个对象,对其序列化,然后通过网络发给一台Unix机器,然后在那里准确无误地重新“还原”。
四、示例代码
下面这个示例相对比较简单,仅仅只是把一个对象序列化保存到文件中。
1、定义一个学生对象,实现Serializable接口,标识这个类的对象是可以序列化的。
/**
* 学生的实体对象
* @author Administrator
*
*/
public class Student implements Serializable {
private String num;
private String name;
public String getNum() {
return num;
}
public void setNum(String num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2、编写两个方法,一个是outputObject方法用于把学生对象序列化保存到d://student.txt文件中,另外一个方法inputObject是反序列化,把文件中的内容重新解析成为对象。
/** * 输出学生列表信息保存到文件中 */ public static void outputObject(ArrayList students) { // 使用对象流保存 try { ObjectOutputStream objectoutput = new ObjectOutputStream( new FileOutputStream("d://student.txt")); // 序列化保存对象 objectoutput.writeObject(students); objectoutput.flush(); objectoutput.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static ArrayList inputObject() { try { ObjectInputStream objectinput = new ObjectInputStream( new FileInputStream("d://student.txt")); ArrayList stus=(ArrayList)objectinput.readObject(); return stus; } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; }
3、测试是否成功,在main方法中,首先有用户输入几个学生对象并封装到ArrayList对象中,然后序列化保存到文本中,你可以查看D盘是否已经序列化成功,当然你打开这个文件,文件的内容你是看不懂的,因为对象已经序列化为二进制的文件内容了。
public static void main(String[] args) { // 获得用户的信息,并封装到ArralyList里 ArrayList stus = new ArrayList(); Scanner scanner = new Scanner(System.in); while (true) { System.out.print("学号:"); String num = scanner.nextLine(); System.out.print("姓名:"); String name = scanner.nextLine(); Student student = new Student(); student.setName(name); student.setNum(num); stus.add(student); System.out.println("是否还有输入:(n/y):"); String input = scanner.nextLine(); if (input.equals("n")) { break; } } // 保存到文件中 outputObject(stus); }
把上面的序列化注释了,现在测试反序列化,看看能否把文件中的内容还原为一个java对象。
public static void main(String[] args) { ArrayList list=inputObject(); for (int i = 0; i < list.size(); i++) { Object object = list.get(i); if (object instanceof Student) { Student stu = (Student) object; System.out.println(stu.getNum() + ":" + stu.getName()); } } }
如果控制台能打印出你刚刚输入的学生信息,那表明序列化和反序列化都成功了。
13.2压缩与解压(1)
一、压缩简介
在平时使用windows操作系统时,压缩与解压都是经常性操作,不同的压缩算法对应不同的压缩格式,一般现在经常使用的压缩格式有.rar,.zip,.7z的压缩格式。
在java系统中,API提供了压缩与解压的工具类可以轻松完成压缩解压的任务,由于更像是工具类,因此这两组不同压缩格式的类被放在util工具集包中,它们看上去更像流类型:
java.util.zip.ZipInputStream/java.util.zip.ZipOutputStream
java.util.zip.GZIPInputStream/java.util.zip.GZIPOutputStream
以上的类都会InputStream和OutputStream进行进一步的修饰,压缩后的数据总是以字节的方式而不是字符的方式进行处理的。
二、ZIP的压缩和解压缩
ZIP是一种很常见的压缩形式,在java中要实现ZIP的压缩主要用到的是java.util.zip这个包里面的类。主要有ZipFile、 ZipOutputStream、ZipInputStream和ZipEntry几个类。ZipOutputStream是用来压缩文件 的,ZipInputStream和ZipFile是用来解压缩文件的,在压缩和解压缩的过程中,ZipEntry都会用到。在java的Zip压缩文件 中,每一个子文件都是一个ZipEntry对象。
1、压缩文件。我们先封装一个方法,实现吧目录下的所有文件压缩,然后在main方法中尝试压缩D:/abc目录的所有文件。代码如下:
public class Zip { public static void zipFile(File inFile, ZipOutputStream zos, String dir) throws IOException { if (inFile.isDirectory()) { File[] files = inFile.listFiles(); for (File file : files) { //如果是目录就递归的压缩 zipFile(file, zos, dir + "\\" + inFile.getName()); } } else { String entryName = null; if (dir!=null&&!dir.equals("")) { entryName = dir + "\\" + inFile.getName(); } else { entryName = inFile.getName(); } //把文件封装成为ZipEntry对象 ZipEntry entry = new ZipEntry(entryName); //添加到ZipOutputStream对象中 zos.putNextEntry(entry); InputStream is = new FileInputStream(inFile); int len = 0; while ((len = is.read()) != -1) { zos.write(len); } is.close(); } } }
然后在main方法中调用这个方法,代码如下:
public static void main(String[] args) { File inFile = new File("D:\\abc"); ZipOutputStream zos; try { zos = new ZipOutputStream(new FileOutputStream("D:\\abc.zip")); zipFile(inFile, zos, ""); zos.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
2、解压缩文件。封装方法如下:
public static void unZipFile(String zipFileName, String targetDir) { try { File file = new File(zipFileName); // 实例化ZipFile,每一个zip压缩文件都可以表示为一个ZipFile ZipFile zipFile = new ZipFile(file); // 实例化一个Zip压缩文件的ZipInputStream对象 ZipInputStream zipInputStream = new ZipInputStream( new FileInputStream(file)); ZipEntry zipEntry = null; // getNextEntry()方法依次拿到每一个ZipEntry对象 while ((zipEntry = zipInputStream.getNextEntry()) != null) { String fileName = zipEntry.getName(); File temp = new File(targetDir + fileName); if (!temp.getParentFile().exists()) { temp.getParentFile().mkdirs(); } OutputStream os = new FileOutputStream(temp); // 通过ZipFile的getInputStream方法拿到具体的ZipEntry的输入流 InputStream is = zipFile.getInputStream(zipEntry); int len = 0; while ((len = is.read()) != -1) { os.write(len); } os.close(); is.close(); } zipInputStream.close(); } catch (ZipException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
修改main函数,注释原来的代码,调用解压缩文件。代码如下:
public static void main(String[] args) { unZipFile("D:\\abc.zip","c:\\"); }
13.3压缩与解压(2)
一、GZIP压缩
GZIP常常用在linxu环境下,是一种非常简单的压缩算法。在Java实现API中,它仅仅包含两个实现类:GZIPInputStream和GZIPOutputStream。 GZIPOutputStream类用于压缩,GZIPInputStream类用于解压缩。
1、压缩,封装方法如下:
public static void compress(InputStream is, OutputStream os) throws Exception { GZIPOutputStream gos = new GZIPOutputStream(os); int count; byte data[] = new byte[8]; while ((count = is.read(data, 0, 8)) != -1) { gos.write(data, 0, count); } gos.finish(); gos.flush(); gos.close(); }
记得完成操作后,调用finish方法和flush方法,在main方法中调用如下:
public static void main(String[] args) { try { FileInputStream inputStream=new FileInputStream("d://ccc.txt"); FileOutputStream outputStream=new FileOutputStream("d://abc.gzip"); compress(inputStream,outputStream); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } }
2、解压缩,封装方法如下:
public static void decompress(InputStream is, OutputStream os) throws Exception { GZIPInputStream gis = new GZIPInputStream(is); int count; byte data[] = new byte[8]; while ((count = gis.read(data, 0, 8)) != -1) { os.write(data, 0, count); } gis.close(); }
在main方法调用如下,把刚才压缩的文件解压缩。
public static void main(String[] args) { try { FileInputStream inputStream=new FileInputStream("d://abc.gzip"); FileOutputStream outputStream=new FileOutputStream("d://ccc.txt"); decompress(inputStream,outputStream); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } }
使用java原生提供这些类实现压缩,可能会有中文乱码等等的问题,大家还可以使用第三方的包实现压缩和解压缩,比如apache的实现就比较好了,这里就暂不做介绍了,大家可自行上网查询相关资料。