将归档后的文件解档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 }
Util

用来申明一个一个文件的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的范围的关系,大家可以去实操一哈。

原文地址:https://www.cnblogs.com/mmzs/p/9469304.html