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文件系统结构详解

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐