1. 程式人生 > >大資料Java基礎(一)-文件歸檔與解檔

大資料Java基礎(一)-文件歸檔與解檔

hadoop中如日誌檔案、天氣記錄文件等都是以文件的形式儲存資料。而大量儲存文件,就會涉及到將有共同特點或者相似性的文件歸為一類等(如按照年份將相同年份的天氣資料文件歸為一類)。

從而需要我們對文件的歸檔和解檔有一定了解。

歸檔就是將多個有共同點的文件歸為一個大的文件;解檔就是將一個大文件,分解成多個獨立的文件。

這裡先普及一下基礎:多個文件歸為一個時,需要確定文件名稱、文件內容,定義文件名稱長度、文件內容長度。順序是定義好文件名稱長度,往裡面寫名稱,在定義好文件內容長度,往裡面加文件內容,然後下一個文件加在這個文件後面步驟和上一個文件一樣。

解檔就是歸檔的逆推。

下面廢話不多說直接上程式

首先是型別轉換工具類就是我上一章的內容

**
 * @ClassName Util
 * @Decription 型別轉換工具類
 * @Author AlexZ
 * @Date 2018-8-1 14:17
 * @Version 1.0
 */
public class Util {
    /**
     * 整型轉換成位元組陣列
     */
    public static byte[] int2Bytes(int i){
        byte[] arr = new byte[4];
        arr[0] = (byte) i;
        arr[1] = (byte) (i >> 8);
        arr[2] = (byte) (i >> 16);
        arr[3] = (byte) (i >> 24);
        return arr ;
    }

    /**
     * 位元組陣列轉換成int
     */
    public static int bytes2Int(byte[] bytes){
        int i0 = bytes[0] & 0xFF;
        int i1 = (bytes[1] & 0xFF) << 8;
        int i2 = (bytes[2] & 0xFF) << 16;
        int i3 = (bytes[3] & 0xFF) << 24;
        return i0 | i1 | i2 | i3;
    }
}

然後是文件的歸檔器

import java.io.*;

/**
 * @ClassName Arcchiver
 * @Decription 歸檔器
 * @Author AlexZ
 * @Date 2018-8-1 13:57
 * @Version 1.0
 */
public class Arcchiver {
    public static void main(String[] args) throws Exception{
        //
        FileOutputStream fos = new FileOutputStream("g:/arch/x.xar",true);
        fos.write(addFile("G:/arch/a.xls"));
        fos.write(addFile("G:/arch/b.java"));
        fos.close();
        //

    }

    /**
     * path : g:/xxx/xxx/a.jpg
     */
    public static byte[] addFile(String path) throws IOException{
        //檔案
        File f = new File(path);
        //檔名
        String fname = f.getName();
        //檔名陣列
        byte[] fnameBytes = fname.getBytes();
        //檔案內容長度
        int len = (int)f.length();
        //計算總長度
        int total = 4 + fnameBytes.length + 4 +len ;
        //初始化總陣列
        byte[] bytes = new byte[total];
        //1.寫入檔名長度
        byte[] fnameLenArr = Util.int2Bytes(fnameBytes.length);
        System.arraycopy(fnameLenArr,0, bytes,0,4);
        //2.寫入檔名本身
        System.arraycopy(fnameBytes,0, bytes,4, fnameBytes.length);
        //3.寫入檔案內容長度
        byte[] fcontentLenArr = Util.int2Bytes(len);
        System.arraycopy(fcontentLenArr,0,bytes,4+fnameBytes.length, 4);
        //4.寫入檔案內容本身
        //讀取檔案內容到陣列中
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        FileInputStream fis = new FileInputStream(f);
        byte[] buf = new byte[1024];
        int len0 = 0;
        while ((len0 = fis.read(buf)) != -1){
            baos.write(buf,0,len0);
        }
        //得到檔案內容
        byte[] fileContentArr = baos.toByteArray();
        System.arraycopy(fileContentArr,0 ,bytes,8 + fnameBytes.length, fileContentArr.length);

        return bytes;
    }

}

最後是解析器 

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName Unarchiver
 * @Decription 解析器
 * @Author AlexZ
 * @Date 2018-8-1 17:09
 * @Version 1.0
 */
public class Unarchiver {
    public static void main(String[] args) throws Exception{
        List<FileBean> files = new ArrayList<FileBean>();
        //
        FileInputStream fis = new FileInputStream("g:/arch/x.xar");

        FileBean fileBean = null;
        //
        while ((fileBean = readNextFile(fis)) != null) {
            files.add(fileBean);
        }
        //關閉流
        fis.close();

        FileOutputStream fos = null;
        //
        for (FileBean fb : files){
            fos = new FileOutputStream("g:/arch/unarch/"+fb.getFileName());
            fos.write(fb.getFileContent());
            fos.close();
        }

    }

    /**
     * 從流中讀取下一個檔案
     * @param fis
     * @return
     */
    public static FileBean readNextFile(FileInputStream fis) throws Exception{
        //
        byte[] bytes4 = new byte[4];
        //讀取四個位元組
        int res = fis.read(bytes4);
        if (res == -1){
            return null;
        }
        //檔名長度
        int fnameLen = Util.bytes2Int(bytes4);

        //檔名陣列
        byte[] fileNameBytes = new byte[fnameLen];
        fis.read(fileNameBytes);

        //得到檔名
        String fileName = new String(fileNameBytes);
        //在讀取4個位元組,作為檔案內容長度
        fis.read(bytes4);
        int fileContLen = Util.bytes2Int(bytes4);

        //讀取檔案內容
        byte[] fileContBytes = new byte[fileContLen];
        fis.read(fileContBytes);

        return new FileBean(fileName,fileContBytes);
    }

}

最後是中間用到的FileBean類

/**
 * @ClassName FileBean
 * @Decription 檔案Bean
 * @Author AlexZ
 * @Date 2018-8-1 20:02
 * @Version 1.0
 */
public class FileBean {
    private String fileName;
    private byte[] fileContent;

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public byte[] getFileContent() {
        return fileContent;
    }

    public void setFileContent(byte[] fileContent) {
        this.fileContent = fileContent;
    }

    public FileBean(){

    }

    public FileBean(String fileName, byte[] fileContent) {
        this.fileName = fileName;
        this.fileContent = fileContent;
    }
}