JAVA——構建FAT32檔案系統的FAT(File Allocation Table檔案分配表)類
阿新 • • 發佈:2020-12-31
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; } } }