将归档后的文件解档01
解档
前情概要
这篇文章是在上一篇文章如何处理零碎小文件归档的基础上写的。
串行化(也叫序列化)
就像过隧道一样,将需要传输的数据排成一排依次传输;
问: java需要这样的技术,为什么呢?
答: 因为在网络中传输数据的时候,所有的数据都是以字节的形式来传输(存储)。
而Java是面相对象编程,那么对象在内存中可能以各种形式存在。那么,当我们需要网络传输或本地存储(实际就是存到磁盘上去)时,我们必须以某种统一的格式(如:xml格式、文本格式、最常见的就是json格式、以对象方式的串行、以二进制方式存储)转化这些数据;这个过程就叫做串行化。
设计思路
按照如下顺序依次将文件一个一个的解档出来:
- 读取4个字节的文件名长度
- 根据读取到的文件名长度,读取文件名
- 读取4个字节的文件内容长度
- 根据读取到的文件内容长度,读取文件内容
注:
其中存储的文件名长度和文件内容长度的字节数是可以自己定义的;并且第一次读取文件名的长度时需要判断是否到了文件末尾,如果是则解档结束。
具体实现方案
同上一篇文章的Util类:
1 package com.mmzs.util; 2 3 /** 4 * @author: mmzs 5 * @date: 2018年8月9日 6 * @Description: 7 * 博客地址:https://www.cnblogs.com/mmzs/p/9282412.html 8 * @version V1.0 9 */ 10 public class Util { 11 /** 12 * 将int转化为字节数组 13 * @return 14 */ 15 public static byte[] int2Bytes(int i){ 16 byte[] arr = new byte[4]; 17 arr[0] = (byte) i; 18 arr[1] = (byte) (i >> 8); 19 arr[2] = (byte) (i >> 16); 20 arr[3] = (byte) (i >> 24); 21 return arr; 22 } 23 24 /** 25 * 将字节数组转化为int 26 */ 27 public static int bytes2Int(byte[] bytes){ 28 int i0 = bytes[0]; 29 int i1 = (bytes[1] & 0xFF) << 8; 30 int i2 = (bytes[2] & 0xFF) << 16; 31 int i3 = (bytes[3] & 0xFF) << 24; 32 return i0 | i1 | i2 | i3; 33 } 34 }
用来申明一个一个文件的FileBean:
package com.mmzs.unarchiver; /** * @author: mmzs * @date: 2018年8月10日 * @Description: * 博客地址:https://www.cnblogs.com/mmzs/p/9282412.html * @version V1.0 */ public class FileBean { private String filename; private byte[] fileContentBytes; public FileBean() { } public FileBean(String filename, byte[] fileContentBytes) { this.filename = filename; this.fileContentBytes = fileContentBytes; } public String getFilename() { return filename; } public byte[] getFileContentBytes() { return fileContentBytes; } public void setFilename(String filename) { this.filename = filename; } public void setFileContentBytes(byte[] fileContentBytes) { this.fileContentBytes = fileContentBytes; } }
实现解档的UnArchiver类:
package com.mmzs.unarchiver; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import com.mmzs.util.Util; /** * @author: mmzs * @date: 2018年8月10日 * @Description: 归档后的文件解档 * 博客地址:https://www.cnblogs.com/mmzs/p/9282412.html * @version V1.0 */ public class UnArchiver { public static void main(String[] args) throws IOException { //存放读取出来的一个个文件 List<FileBean> files = new ArrayList<FileBean>(); //通过文件输入流,将指定文件转化为流 FileInputStream fis = new FileInputStream("d:/test/x.xar"); FileBean fileBean = null; //将接档后的文件一个一个读取到List数组中 while ((fileBean = readNextFile(fis)) != null) { files.add(fileBean); } //关闭流 fis.close(); FileOutputStream fos = null; //将文件解压到指定了目录下 for (FileBean fb : files) { fos = new FileOutputStream("d:/test/unarch/"+fb.getFilename()); fos.write(fb.getFileContentBytes()); fos.close(); } System.out.println("解档后的文件均已解档到"+"d:/test/unarch/"+"目录下"); } /** * 从文件输入流中一个文件一个文件的读取 * @throws IOException */ public static FileBean readNextFile(FileInputStream fis) throws IOException { //因为归档程序Archiver中设置的存储文件名的长度的字节数组长度为4 byte[] bytes4 = new byte[4]; // 1、读取4个字节的bytes4数组中的文件名长度 int res = fis.read(bytes4); if (res == -1) { return null; } //2、 // 根据读取到的bytes4字节数组中存储的文件名长度 int fnameLen = Util.bytes2Int(bytes4); //读取文件名 byte[] fnameBytes = new byte[fnameLen]; fis.read(fnameBytes); //得到文件名 String fname = new String(fnameBytes); // 3、读取4个字节的bytes4数组中的文件内容长度 fis.read(bytes4); //4、 // 根据读取到的文件内容长度 int fcontentLen = Util.bytes2Int(bytes4); System.out.println("文件长度"+fcontentLen); //读取文件内容 byte[] fcontentBytes = new byte[fcontentLen]; fis.read(fcontentBytes); return new FileBean(fname, fcontentBytes); } }
最后附一张工程截图:
解档效果图:
不过遇到一个问题,就是 当图片太大的时候,归档后的文件在利用这种方式解档时会出现问题,不出意外,应该是int的范围的关系,大家可以去实操一哈。