Maven
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
解决方案
DMR
package cn.edu.zstu.fms.storage;
import lombok.Data;
/**
* 是DOS引导记录,也称为操作系统引导记录,在DBR之后往往会有一些保留扇区。
* @see <a href="https://blog.51cto.com/dengqi/1349327">FAT32文件系统详解</a>
* @author ShenTuZhiGang
* @version 1.0.0
* @date 2020-12-29 18:28
*/
@Data
public class DOSBootRecord {
/**
* 跳转指令 开始字节位置
*/
public static final int JUMP_COMMAND_START =0;
/**
* 跳转指令 长度
*/
public static final int JUMP_COMMAND_LENGTH =2;
/**
* OEM代号 开始字节位置
*/
public static final int OEM_CODE_START =3;
/**
* OEM代号 长度
*/
public static final int OEM_CODE_LENGTH =8;
/**
* BPB 开始字节位置
*/
public static final int BIOS_PARAMETER_BLOCK_START = 11;
/**
* BPB 长度
*/
public static final int BIOS_PARAMETER_BLOCK_LENGTH =79;
/**
* 引导程序代码 开始字节位置
*/
public static final int BOOTLOADER_CODE_START = 90;
/**
* 引导程序代码 长度
*/
public static final int BOOTLOADER_CODE_LENGTH =420;
/**
* BPB 开始字节位置
*/
public static final int END_SIGN_START = 510;
/**
* 结束标志 长度
*/
public static final int END_SIGN_LENGTH =2;
/**
* 源数据
*/
private byte[] source;
/**
* 跳转指令
* 占2字节,它将程序执行流程跳转到引导程序处。
* 跳转指令后,一条空的指令NOP(90H)
* @see <a href="https://blog.csdn.net/pnzrk/article/details/88943746">FAT32</a>
*/
private byte[] jumpCommand = new byte[2];
/**
* OEM代号
* 占8字节,其内容由创建该文件系统的OEM厂商具体安排。
*/
private byte[] oemCode = new byte[8];
/**
* BPB BIOS参数块
* BIOS Parameter Block
* FAT32的BPB从DBR的第12个字节开始,占用79字节,记录了有关该文件系统的重要信息
*/
private BIOSParameterBlock biosParameterBlock;
/**
* 引导程序代码
* FAT32的DBR引导程序占用420字节,对于没有安装操作系统的分区来说这段程序是没有用处的。
*/
private byte[] bootloaderCode = new byte[420];
/**
* 结束标志
* 0xAA55
*/
private byte[] endSign = new byte[2];
/**
*
* @param source
*/
public DOSBootRecord(byte[] source){
this.source = source;
//跳转指令
jumpCommand = new byte[JUMP_COMMAND_LENGTH];
System.arraycopy(this.source, JUMP_COMMAND_START, jumpCommand, 0, JUMP_COMMAND_LENGTH);
//OEM代号
oemCode = new byte[OEM_CODE_LENGTH];
System.arraycopy(this.source, OEM_CODE_START, oemCode, 0, OEM_CODE_LENGTH);
//BIOS参数块
byte[] biosParameterBlockSource = new byte[BIOS_PARAMETER_BLOCK_LENGTH];
System.arraycopy(this.source, BIOS_PARAMETER_BLOCK_START, biosParameterBlockSource, 0, BIOS_PARAMETER_BLOCK_LENGTH);
this.biosParameterBlock = new BIOSParameterBlock(biosParameterBlockSource);
//引导程序代码
bootloaderCode = new byte[BOOTLOADER_CODE_LENGTH];
System.arraycopy(this.source, BOOTLOADER_CODE_START, bootloaderCode, 0, BOOTLOADER_CODE_LENGTH);
//结束标志
endSign = new byte[END_SIGN_LENGTH];
System.arraycopy(this.source, END_SIGN_START, endSign, 0, END_SIGN_LENGTH);
}
}
BPB
package cn.edu.zstu.fms.storage;
import lombok.Data;
import java.io.Serializable;
import java.nio.charset.Charset;
/**
* BIOS参数块
* BIOS Parameter Block
* FAT32的BPB从DBR的第12个字节开始,占用79字节,记录了有关该文件系统的重要信息
* @see <a href="https://blog.csdn.net/pnzrk/article/details/88943746">FAT32</a>
* @author ShenTuZhiGang
* @version 1.0.0
* @date 2020-12-29 19:23
*/
@Data
public class BIOSParameterBlock implements Serializable {
/*
* 字节偏移
*/
/**
* 每扇区字节数 字节偏移
*/
public static final Byte SECTOR_BYTE_NUM_OFFSET_POSITION = 0x0B - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* 每簇扇区数 字节偏移
*/
public static final Byte CLUSTER_SECTOR_NUM_OFFSET_POSITION = 0x0D - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* DOS保留扇区数 字节偏移
*/
public static final Byte DOS_RESERVED_SECTOR_NUM_OFFSET_POSITION = 0x1E - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* FAT个数 字节偏移
*/
public static final Byte FILE_ALLOCATION_TABLE_NUM_OFFSET_POSITION = 0x10 - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* 未用 字节偏移
*/
public static final Byte UNUSED_1_OFFSET_POSITION = 0x11 - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* 未用 字节偏移
*/
public static final Byte UNUSED_2_OFFSET_POSITION = 0x13 - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* 介质描述符 字节偏移
*/
public static final Byte MEDIA_DESCRIPTOR_OFFSET_POSITION = 0x15 - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* 未用 字节偏移
*/
public static final Byte UNUSED_3_OFFSET_POSITION = 0x16 - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* 每磁道扇区数 字节偏移
*/
public static final Byte TRACK_SECTOR_NUM_OFFSET_POSITION = 0x18 - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* 磁头数 字节偏移
*/
public static final Byte HEAD_NUM_OFFSET_POSITION = 0x1A - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* 隐藏扇区数 字节偏移
*/
public static final Byte HIDDEN_SECTOR_OFFSET_POSITION = 0x1C - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* 分区扇区总数 字节偏移
*/
public static final Byte PARTITION_SECTOR_NUM_OFFSET_POSITION = 0x20 - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/*
* 扩展BPB
*/
/**
* 每FAT扇区数 字节偏移
*/
public static final Byte FAT_SECTOR_NUM_OFFSET_POSITION = 0x24 - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* 标记 字节偏移
*/
public static final Byte SIGN_OFFSET_POSITION = 0x28 - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* 版本 字节偏移
*/
public static final Byte VERSION_OFFSET_POSITION = 0x2A - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* 根目录首簇号 字节偏移
*/
public static final Byte ROOT_CLUSTER_NUMBER_OFFSET_POSITION = 0x2C - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* 文件系统信息扇区号 字节偏移
*/
public static final Byte FILE_SYSTEM_INFORMATION_SECTOR_NUMBER_OFFSET_POSITION = 0x30 - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* DBR备份扇区号 字节偏移
*/
public static final Byte BACKUP_SECTOR_NUMBER_OFFSET_POSITION = 0x32 - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* 保留 字节偏移
*/
public static final Byte RETAIN_OFFSET_POSITION = 0x34 - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* BIOS驱动器号 字节偏移
*/
public static final Byte bios_Drive_Number_OFFSET_POSITION = 0x40 - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* 未用 字节偏移
*/
public static final Byte extend_Boot_Flag_OFFSET_POSITION = 0x41 - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* 扩展引导标记 字节偏移
*/
public static final Byte UNUSED_4_OFFSET_POSITION = 0x42 - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* 卷序列号 字节偏移
*/
public static final Byte VOLUME_SERIAL_NUMBER_OFFSET_POSITION = 0x43 - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* 卷标 字节偏移
*/
public static final Byte VOLUME_LABEL_OFFSET_POSITION = 0x47 - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/**
* 文件系统类型 字节偏移
*/
public static final Byte FILE_SYSTEM_TYPE_OFFSET_POSITION = 0x52 - DOSBootRecord.BIOS_PARAMETER_BLOCK_START;
/*
* 长度
*/
/**
* 每扇区字节数 长度
*/
public static final Byte SECTOR_BYTE_NUM_LENGTH = 2;
/**
* 每簇扇区数 长度
*/
public static final Byte CLUSTER_SECTOR_NUM_LENGTH = 1;
/**
* DOS保留扇区数 长度
*/
public static final Byte DOS_RESERVED_SECTOR_NUM_LENGTH = 2;
/**
* FAT个数 长度
*/
public static final Byte FILE_ALLOCATION_TABLE_NUM_LENGTH = 1;
/**
* 未用 长度
*/
public static final Byte UNUSED_1_LENGTH = 2;
/**
* 未用 长度
*/
public static final Byte UNUSED_2_LENGTH = 2;
/**
* 介质描述符 长度
*/
public static final Byte MEDIA_DESCRIPTOR_LENGTH = 1;
/**
* 未用 长度
*/
public static final Byte UNUSED_3_LENGTH = 2;
/**
* 每磁道扇区数 长度
*/
public static final Byte TRACK_SECTOR_NUM_LENGTH = 2;
/**
* 磁头数 长度
*/
public static final Byte HEAD_NUM_LENGTH = 2;
/**
* 隐藏扇区数 长度
*/
public static final Byte HIDDEN_SECTOR_LENGTH = 4;
/**
* 分区扇区总数 长度
*/
public static final Byte PARTITION_SECTOR_NUM_LENGTH = 4;
/*
* 扩展BPB
*/
/**
* 每FAT扇区数 长度
*/
public static final Byte FAT_SECTOR_NUM_LENGTH = 4;
/**
* 标记 长度
*/
public static final Byte SIGN_LENGTH = 2;
/**
* 版本 长度
*/
public static final Byte VERSION_LENGTH = 2;
/**
* 根目录首簇号 长度
*/
public static final Byte ROOT_CLUSTER_NUMBER_LENGTH = 4;
/**
* 文件系统信息扇区号 长度
*/
public static final Byte FILE_SYSTEM_INFORMATION_SECTOR_NUMBER_LENGTH = 2;
/**
* DBR备份扇区号 长度
*/
public static final Byte BACKUP_SECTOR_NUMBER_LENGTH = 2;
/**
* 保留 长度
*/
public static final Byte RETAIN_LENGTH = 12;
/**
* BIOS驱动器号 长度
*/
public static final Byte bios_Drive_Number_LENGTH = 1;
/**
* 未用 长度
*/
public static final Byte extend_Boot_Flag_LENGTH = 1;
/**
* 扩展引导标记 长度
*/
public static final Byte UNUSED_4_LENGTH = 1;
/**
* 卷序列号 长度
*/
public static final Byte VOLUME_SERIAL_NUMBER_LENGTH = 4;
/**
* 卷标 长度
*/
public static final Byte VOLUME_LABEL_LENGTH = 11;
/**
* 文件系统类型 长度
*/
public static final Byte FILE_SYSTEM_TYPE_LENGTH = 8;
/**
* 源数据
*/
private byte[] source;
/**
* 每扇区字节数
* 字节偏移 0x0B
* 长度 2个字节
* 记录每个逻辑扇区的大小,其常见的值为512,但是并不是固定的值。
* 该值可以由程序定义,合法值包括512、1024、2048、4096。
*/
private Short sectorByteNum;
/**
* 每簇扇区数
* 字节偏移 0x0D
* 长度 1个字节
* 记录着文件系统的簇大小,即由多少个扇区组成一个簇。
* 簇是FAT12,FAT16及FAT32文件系统下数据的最小存储单元,
* 一个簇由一组连续的扇区组成,簇所含的扇区数必须是2的整数次幂,
* 如1,2,4,8,16,32,64,128.
* 在Windows 2000以前族最大值为64扇区,之后最大值为128。
* 在FAT文件系统中,所有的簇是从2开始编号,
* 每个簇都有一个自己的地址编号,
* 但是所有的簇都位于数据区,在数据区之前没有簇。
*/
private Byte clusterSectorNum;
/**
* DOS保留扇区数
* 字节偏移 0x0E
* 长度 1个字节
* DBR到FAT1表之间的扇区数,或者说是FAT1的开始扇区号,对于FAT32文件系统来说,该值的范围是32扇区到38扇区之间。
*/
private Short dosReservedSectorNum;
/**
* FAT个数
* 字节偏移 0x10
* 长度 1个字节
* 一般为2
*/
private Byte FATNum;
/**
* 介质描述符
* 字节偏移 0x15
* 长度 1个字节
* 描述磁盘介质的参数,根据磁盘性质的不同,取不同的值。0xF8标准值,可移动存储介质,常用 0xF0
*/
private Byte mediaDescriptor;
/**
* 每磁道扇区数
* 字节偏移 0x18
* 长度 1个字节
* 一般其值为63
*/
private Short trackSectorNum;
/**
* 磁头数
* 字节偏移 0x1A
* 长度 1个字节
* 一般为255
*/
private Short headNum;
/**
* 隐藏扇区数
* 字节偏移 0x1C
* 长度 1个字节
* 是MBR到DBR之间的扇区数,对于扩展分区中逻辑驱动顺来说,是其EBR到DBR。可以为0。
*/
private Integer hiddenSector;
/**
* 分区扇区总数
* 字节偏移 0x20
* 长度 4个字节
* 分区的总扇区数,也就是FAT32分区的大小
*/
private Integer partitionSectorNum;
/*
* 扩展BPB
*/
/**
* 每FAT扇区数
* 字节偏移 0x24
* 长度 1个字节
* FAT表占用扇区数
*/
private Integer FATSectorNum;
/**
* 标记
* 字节偏移 0x28
* 长度 1个字节
* FAT32是否可用,2为可用,此域FAT32 特有
*/
private Short sign;
/**
* 版本
* 字节偏移 0x2A
* 长度 1个字节
* FAT32版本号0.0,FAT32特有
*/
private Short version;
/**
* 根目录首簇号
* 字节偏移 0x2C
* 长度 4个字节
* 分区在格式化的时候,
* 格式化程序会在数据区中指派一个簇作为FAT32的根目录的开始,并把该簇号记录在BPB中。
* 通常都是把数据区中的第一簇分配给根目录使用,也就是2号簇。
*/
private Integer rootClusterNumber;
/**
* 文件系统信息扇区号
* 字节偏移 0x30
* 长度 2个字节
* FAT32文件系统在DBR的保留扇区中安排了一个文件系统信息扇区,用以记录数据区中空闲簇的数量及下一个可用的空闲簇的簇号,
* 该扇区一般在分区的1号扇区,也就是紧跟在DBR之后的一个扇区。
* FSINFO(文件系统信息扇区)扇区号1,该扇区为操作系统提供关于空簇总数及下一可用簇的信息
*/
private Short fileSystemInformationSectorNumber;
/**
* DBR备份扇区号
* 字节偏移 0x32
* 长度 2个字节
* FAT32文件系统在DBR的保留扇区中安排了一个DBR的备份,
* 一般在6号扇区,也就是分区的第7个扇区,该备份扇区与原DBR扇区的内容完全一样,如果原DBR遭到破坏,可以用备份扇区号修复。
*/
private Short backupSectorNumber;
/**
* BIOS驱动器号
* 字节偏移 0x40
* 长度 1个字节
* 这是BIOS的INT 13H所描述的设备号码,一般硬盘为80H,一般软盘为00H等
*/
private Byte biosDriveNumber;
/**
* 扩展引导标记
* 字节偏移 0x41
* 长度 1个字节
* 用来确认后面的三个参数是否有效,FAT为29H
*/
private Byte extendBootFlag;
/**
* 卷序列号
* 字节偏移 0x43
* 长度 4个字节
* 磁盘序列号,通常为一随机数
*/
private Integer volumeSerialNumber;
/**
* 卷标
* 字节偏移 0x47 {@link cn.edu.zstu.fms.storage.BIOSParameterBlock#VOLUME_LABEL_OFFSET_POSITION }
* 长度 11个字节 {@link cn.edu.zstu.fms.storage.BIOSParameterBlock#VOLUME_LABEL_LENGTH }
* 用户设置的卷标ASCII,如果没有则4E 4F 20 4E 41 4D 45 20 20 20 20 即NO NAME。如果建立文件系统的时候指定了卷标,会保存在此
*/
private Character[] volumeLabel;
/**
* 文件系统类型
* 字节偏移 0x52 {@link cn.edu.zstu.fms.storage.BIOSParameterBlock#FILE_SYSTEM_TYPE_OFFSET_POSITION }
* 长度 8个字节 {@link cn.edu.zstu.fms.storage.BIOSParameterBlock#FILE_SYSTEM_TYPE_LENGTH }
* 使用ASCII码记录当前分区的文件系统类型,46 41 54 33 32 20 20 20即FAT32
*/
private Character[] fileSystemType;
/**
*
* @param source
*/
public BIOSParameterBlock(byte[] source){
this.source = source;
}
}
class ByteUtil {
public static byte[] getBytes(short data) {
byte[] bytes = new byte[2];
bytes[0] = (byte) (data & 0xff);
bytes[1] = (byte) ((data & 0xff00) >> 8);
return bytes;
}
public static byte[] getBytes(char data) {
byte[] bytes = new byte[2];
bytes[0] = (byte) (data);
bytes[1] = (byte) (data >> 8);
return bytes;
}
public static byte[] getBytes(int data) {
byte[] bytes = new byte[4];
bytes[0] = (byte) (data & 0xff);
bytes[1] = (byte) ((data & 0xff00) >> 8);
bytes[2] = (byte) ((data & 0xff0000) >> 16);
bytes[3] = (byte) ((data & 0xff000000) >> 24);
return bytes;
}
public static byte[] getBytes(long data) {
byte[] bytes = new byte[8];
bytes[0] = (byte) (data & 0xff);
bytes[1] = (byte) ((data >> 8) & 0xff);
bytes[2] = (byte) ((data >> 16) & 0xff);
bytes[3] = (byte) ((data >> 24) & 0xff);
bytes[4] = (byte) ((data >> 32) & 0xff);
bytes[5] = (byte) ((data >> 40) & 0xff);
bytes[6] = (byte) ((data >> 48) & 0xff);
bytes[7] = (byte) ((data >> 56) & 0xff);
return bytes;
}
public static byte[] getBytes(float data) {
int intBits = Float.floatToIntBits(data);
return getBytes(intBits);
}
public static byte[] getBytes(double data) {
long intBits = Double.doubleToLongBits(data);
return getBytes(intBits);
}
public static byte[] getBytes(String data, String charsetName) {
Charset charset = Charset.forName(charsetName);
return data.getBytes(charset);
}
public static byte[] getBytes(String data) {
return getBytes(data, "UTF-8");
}
public static short getShort(byte[] bytes) {
return (short) ((0xff & bytes[0]) | (0xff00 & (bytes[1] << 8)));
}
public static char getChar(byte[] bytes) {
return (char) ((0xff & bytes[0]) | (0xff00 & (bytes[1] << 8)));
}
public static int getInt(byte[] bytes) {
return (0xff & bytes[0]) | (0xff00 & (bytes[1] << 8)) | (0xff0000 & (bytes[2] << 16)) | (0xff000000 & (bytes[3] << 24));
}
public static long getLong(byte[] bytes) {
return(0xffL & (long)bytes[0]) | (0xff00L & ((long)bytes[1] << 8)) | (0xff0000L & ((long)bytes[2] << 16)) | (0xff000000L & ((long)bytes[3] << 24))
| (0xff00000000L & ((long)bytes[4] << 32)) | (0xff0000000000L & ((long)bytes[5] << 40)) | (0xff000000000000L & ((long)bytes[6] << 48)) | (0xff00000000000000L & ((long)bytes[7] << 56));
}
public static float getFloat(byte[] bytes) {
return Float.intBitsToFloat(getInt(bytes));
}
public static double getDouble(byte[] bytes) {
long l = getLong(bytes);
System.out.println(l);
return Double.longBitsToDouble(l);
}
public static String getString(byte[] bytes, String charsetName) {
return new String(bytes, Charset.forName(charsetName));
}
public static String getString(byte[] bytes) {
return getString(bytes, "UTF-8");
}
}
参考文章
FAT32
FAT32文件系统详解
javadoc中{@link}与@see的简单使用以及区别
FAT32文件系统快速入门
FAT32文件系统结构详解