1. 程式人生 > 其它 >JAVA——構建FAT32檔案系統的FAT(File Allocation Table檔案分配表)類

JAVA——構建FAT32檔案系統的FAT(File Allocation Table檔案分配表)類

技術標籤:# JAVAJAVAFATFAT32

Maven

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </dependency>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-launcher</artifactId>
            <version>1.7.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.7.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
            <version>5.7.0</version>
            <scope>test</scope>
        </dependency>

解決方案

package cn.edu.zstu.fms.storage;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * FAT表結構及作用
 * 1、FAT32檔案一般有兩份FAT,他們由格式化程式在對分割槽進行格式化時建立,FAT1是主,FAT2是備份。
 * 2、FAT1跟在DBR之後,其具體地址由DBR的BPB引數中指定,FAT2跟在FAT1的後面。
 * 3、FAT表由FAT表項構成,我們把FAT表項簡稱FAT項,每個FAT項佔用4位元組。
 * 4、每個FAT項都有一個固定的編號,這個編號從0開始。
 * 5、FAT表項的前兩個FAT項為檔案系統保留使用,0號FAT為介質型別,1號FAT為檔案系統錯誤標誌。
 * 6、分割槽的資料區中每個簇都會對映到FAT表中的唯一一個FAT項,因為0號FAT和1號FAT被系統佔用,使用者的資料從2號FAT開始記錄。
 * 7、如果某個檔案佔用很多個簇,則第一個FAT項記錄下一個FAT項的編號(既簇號),如果這個檔案結束了,則用“0F FF FF FF”表示。
 * 8、分割槽格式化後,使用者檔案以簇為單位存放在資料區中,一個檔案至少佔用一個簇。
 * 9、FAT的主要作用是標明分割槽儲存的介質以及簇的使用情況。
 * @see <a href="https://blog.51cto.com/dengqi/1349327">FAT32檔案系統詳解</a>
 * @see <a href="https://blog.csdn.net/pnzrk/article/details/88943746">FAT32</a>
 * @author ShenTuZhiGang
 * @version 1.0.0
 * @date 2020-12-16 22:42
 */
public class FileAllocationTable {
    /**
     * 源資料
     */
    private byte[] source;

    /**
     * hash表
     */
    private Map<Integer,Integer> table;

    public FileAllocationTable(){
        this(new byte[512*2]);
    }
    public FileAllocationTable(byte[] bytes){
        table = new HashMap<>();
        setSource(bytes);
    }

    public byte[] getSource() {
        return source;
    }

    public void setSource(byte[] source) {
        this.source = source;
        for (int i=0; i<this.source.length; i+=4){
            Integer item= getItem(i);
            table.put(i/4,item);
        }
    }
    private void setItem(int pos,Integer data) {
        byte[] bytes = new byte[4];
        this.source[0 + pos] = (byte) (data & 0xff);
        this.source[1 + pos] = (byte) ((data & 0xff00) >> 8);
        this.source[2 + pos] = (byte) ((data & 0xff0000) >> 16);
        this.source[3 + pos] = (byte) ((data & 0xff000000) >> 24);
    }
    /**
     * 獲取一個FAT項
     * @param pos 偏移位置
     * @return
     */
    private Integer getItem(int pos) {
        return (0xff & this.source[0 + pos])
            | (0xff00 & (this.source[1 + pos] << 8))
            | (0xff0000 & (this.source[2 + pos] << 16))
            | (0xff000000 & (this.source[3 + pos] << 24));
    }

    @Override
    public String toString() {
        String res = "";
        for (int i = 0; i < this.source.length; i++) {
            String temp = Integer.toHexString(this.source[i] & 0xFF);
            res = res + ((temp.length() == 1)?"0" + temp:"" + temp) + (i==this.source.length - 1?"":((i+1)%16==0?"\n":"\t"));
        }
        return res;
    }
    /**
     * 新增一個FAT
     * @param id ID
     * @param location 值
     */
    public void save(Integer id,Integer location){
        table.put(id,location);
        setItem(id,location);
    }
    /**
     * 新增一個FAT
     * @param id ID
     * @param item 值
     */
    public void save(Integer id,FileAllocationTableItem item){
        save(id,item.getValue());
    }

    /**
     * 刪除一個FAT
     * @param id ID
     */
    public void  clear(Integer id){
        save(id,FileAllocationTableItem.EMPTY_CLUSTER_FAT_VALUE);
    }

    /**
     * 標記壞簇     
     * @param id ID
     */
    public void bad(Integer id){
        save(id,FileAllocationTableItem.BAD_CLUSTER_FAT_VALUE);
    }
}

package cn.edu.zstu.fms.storage;

/**
 * 表項數值
 * 對應含義
 * <p>
 * 0x00000000
 * 空閒簇,即表示可用
 * <p>
 * 0x00000001
 * 保留簇
 * <p>
 * 0x00000002 - 0x0FFFFFEF
 * 被佔用的簇,其值指向下一個簇號
 * <p>
 * 0x0FFFFFF0 - 0x0FFFFFF6
 * 保留值
 * <p>
 * 0x0FFFFFF7
 * 壞簇
 * <p>
 * 0x0FFFFFF8 - 0x0FFFFFFF
 * 檔案最後一個簇
 *
 * @see <a href="https://blog.51cto.com/dengqi/1349327">FAT32檔案系統詳解</a>
 * @see <a href="https://blog.csdn.net/pnzrk/article/details/88943746">FAT32</a>
 * @author ShenTuZhiGang
 * @version 1.0.0
 * @date 2020-12-16 22:42
 */
public enum FileAllocationTableItem {
    /*
     * 0號FAT為介質型別
     * 由於簇號起始於2, 所以FAT表的0號表項與1號表項不予任何簇對應。 FAT32 的0號表項值總是“F8FFFF0F”
     * 注意: 可以搜尋扇區偏移0位元組處的該值(F8FFF0F)以查詢FAT表。
     * 模擬中由於1扇區/簇,所以簇號起始於6
     */
    ZERO_FAT_VALUE(0xF8FFFF0F),
    /*
     * 1號FAT為檔案系統錯誤標誌
     * 1號表項可能被用於記錄“髒標誌”, 以說明檔案系統沒有被正常解除安裝或者磁碟表面存在錯誤。
     * 不過此值似乎不重要,正常情況下,1號表項值“FFFFFFFF”或“FFFFFF0F”。
     */
    ONE_FAT_VALUE(0xFFFFFF0F),
    /*
     * 空閒簇,即表示可用
     */
    EMPTY_CLUSTER_FAT_VALUE(0x00000000),
    /*
     * 保留簇
     */
    RESERVED_CLUSTER_FAT_VALUE(0x00000001),
    /*
     * 被佔用的簇,其值指向下一個簇號
     */
    USED_CLUSTER_FAT_VALUE(0x00000002),
    /*
     * 保留值
     */
    RESERVED_VALUE(0x0FFFFFF0),
    /*
     * 壞簇
     */
    BAD_CLUSTER_FAT_VALUE(0x0FFFFFF7),
    /*
     * 檔案最後一個簇
     */
    END_CLUSTER_FAT_VALUE(0x0FFFFFF8),
    /*
     * 未知值
     */
    UNKNOWN_VALUE(0xFFFFFFF0);

    FileAllocationTableItem(Integer value) {
        this.value = value;
    }

    private Integer value;

    public Integer getValue() {
        return value;
    }

    public static FileAllocationTableItem parse(Integer value) {
        if (value == 0xF8FFFF0F) {
            return FileAllocationTableItem.ZERO_FAT_VALUE;
        } else if (value == 0xFFFFFFFF || value == 0xFFFFFF0F) {
            return FileAllocationTableItem.ONE_FAT_VALUE;
        } else if (value == 0x00000001) {
            return FileAllocationTableItem.RESERVED_CLUSTER_FAT_VALUE;
        } else if (value >= 0x00000002 && value <= 0x0FFFFFEF) {
            //模擬中由於1扇區/簇,所以簇號實際上起始於6
            return FileAllocationTableItem.USED_CLUSTER_FAT_VALUE;
        } else if (value >= 0x0FFFFFF0 && value <= 0x0FFFFFF6) {
            return FileAllocationTableItem.RESERVED_VALUE;
        } else if (value == 0x0FFFFFF7) {
            return FileAllocationTableItem.BAD_CLUSTER_FAT_VALUE;
        } else if (value >= 0x0FFFFFF8 && value <= 0x0FFFFFFF) {
            return FileAllocationTableItem.END_CLUSTER_FAT_VALUE;
        } else {
            return UNKNOWN_VALUE;
        }
    }
}

參考文章

Java中File使用--建立檔案

FAT32

FAT32檔案系統詳解

javadoc中{@link}與@see的簡單使用以及區別

FAT32檔案系統快速入門

FAT32檔案系統結構詳解