格式化 分配单元大小(手写FAT32(七)—文件操作)

Posted

篇首语:只要自己上进,不怕人家看轻。本文由小常识网(cha138.com)小编为大家整理,主要介绍了格式化 分配单元大小(手写FAT32(七)—文件操作)相关的知识,希望对你有一定的参考价值。

格式化 分配单元大小(手写FAT32(七)—文件操作)

回顾

在FAT32文件系统分析(六)知道了在数据区主要组成部分为:3字节跳转指令、保留区、FAT区、引导代码、启动标记。

其中,保留区中包含了整个数据区中的基本信息,为此创建了两个结构体_bpb_t 与_fat32_hdr_t。

/** * FAT文件系统的BPB结构 */typedef struct _bpb_t     u8_t BS_jmpBoot[3];                 // 跳转指令    u8_t BS_OEMName[8];                 // OEM名称    u16_t BPB_BytsPerSec;               // 每扇区字节数    u8_t BPB_SecPerClus;                // 每簇扇区数    u16_t BPB_RsvdSecCnt;               // 保留区扇区数    u8_t BPB_NumFATs;                   // FAT表项数    u16_t BPB_RootEntCnt;               // 根目录项目数    u16_t BPB_TotSec16;                 // 总的扇区数    u8_t BPB_Media;                     // 媒体类型    u16_t BPB_FATSz16;                  // FAT表项大小    u16_t BPB_SecPerTrk;                // 每磁道扇区数    u16_t BPB_NumHeads;                 // 磁头数    u32_t BPB_HiddSec;                  // 隐藏扇区数    u32_t BPB_TotSec32;                 // 总的扇区数 bpb_t;/** * BPB中的FAT32结构 */typedef struct _fat32_hdr_t     u32_t BPB_FATSz32;                  // FAT表的字节大小    u16_t BPB_ExtFlags;                 // 扩展标记    u16_t BPB_FSVer;                    // 版本号    u32_t BPB_RootClus;                 // 根目录的簇号    u16_t BPB_FsInfo;                   // fsInfo的扇区号    u16_t BPB_BkBootSec;                // 备份扇区    u8_t BPB_Reserved[12];    u8_t BS_DrvNum;                     // 设备号    u8_t BS_Reserved1;    u8_t BS_BootSig;                    // 扩展标记    u32_t BS_VolID;                     // 卷序列号    u8_t BS_VolLab[11];                 // 卷标名称    u8_t BS_FileSysType[8];             // 文件类型名称 fat32_hdr_t;

这两个结构体包含的内容十分的详细,不过有许多信息在实际过程的时候使用的频率很低,且如果在每次调用disk_read_sector读取这一片扇区的时候,那必须要用一个缓冲区来存储这两个结构体,这样不仅会浪费内存而且效率不高。因此,有必要定义一个新的结构体来存储这_bpb_t 与fat32_hdr_t中的关键信息。

/** * xfat结构 */typedef struct _xfat_t     u32_t fat_start_sector;             // FAT表起始扇区    u32_t fat_tbl_nr;                   // FAT表数量    u32_t fat_tbl_sectors;              // 每个FAT表的扇区数    u32_t total_sectors;                // 总扇区数    xdisk_part_t * disk_part;           // 对应的分区信息 xfat_t;xfat_err_t xfat_open(xfat_t * xfat, xdisk_part_t * xdisk_part);
#include "xfat.h"#include "xdisk.h"extern u8_t temp_buffer[512];      // todo: 缓存优化/** * 从dbr中解析出fat相关配置参数 * @param dbr 读取的设备dbr * @return */static xfat_err_t parse_fat_header (xfat_t * xfat, dbr_t * dbr)     xdisk_part_t * xdisk_part = xfat->disk_part;    // 解析DBR参数,解析每个FAT表的扇区数,就是FAT表的字节大小    xfat->fat_tbl_sectors = dbr->fat32.BPB_FATSz32;    // 开启FAT镜像,只刷新一个FAT表    if (dbr->fat32.BPB_ExtFlags & (1 << 7))         u32_t table = dbr->fat32.BPB_ExtFlags & 0xF;        //FAT表起始扇区 = 保留区扇区数+具体磁盘分区起始地址+FAT表的镜像数目*FAT表的字节大小。        xfat->fat_start_sector = dbr->bpb.BPB_RsvdSecCnt + xdisk_part->start_sector + table * xfat->fat_tbl_sectors;        xfat->fat_tbl_nr = 1;        // 禁用磁盘分区    else             //FAT表的起始扇区 = 保留扇区数+具体磁盘分区的起始地址        xfat->fat_start_sector = dbr->bpb.BPB_RsvdSecCnt + xdisk_part->start_sector;        //FAT表项数        xfat->fat_tbl_nr = dbr->bpb.BPB_NumFATs;        xfat->total_sectors = dbr->bpb.BPB_TotSec32;    return FS_ERR_OK;/** * 初始化FAT项 * @param xfat xfat结构 * @param disk_part 分区结构 * @return */xfat_err_t xfat_open(xfat_t * xfat, xdisk_part_t * xdisk_part)     dbr_t * dbr = (dbr_t *)temp_buffer;    xdisk_t * xdisk = xdisk_part->disk;    xfat_err_t err;    xfat->disk_part = xdisk_part;    // 读取磁盘中第一个分区中的第一个扇区,就是获得第一个分区的DBR信息    err = xdisk_read_sector(xdisk, (u8_t *) dbr, xdisk_part->start_sector, 1);    if (err < 0)         return err;        // 解析dbr参数中的fat相关信息    err = parse_fat_header(xfat, dbr);    if (err < 0)         return err;        return FS_ERR_OK;

解析

FAT镜像:FAT镜像是一种文件系统镜像,它使用了FAT(File Allocation Table)文件系统,通常用于在计算机系统之间传输文件或备份数据。

数据区解析

上面我们解析了保留区、FAT区的内容,接下来就需要解析数据区中有什么内容了。

数据区的内容:存储目录和文件内容,其中FAT的数据是通过簇来实现的,注意的是数据开始的簇号为2.

每个簇包含一个扇区和多个扇区,在格式化磁盘的时候会要求分配单元的大小,这里的分配单元指的就是簇的大小,这里的大小都是2的N次幂。

在给文件分配簇的时候,即使该文件占用的空间少于1个簇的时候,都会分配一个簇。就是不足一簇分配整簇。

读取数据区中的一个文件

无论是在逻辑上还是在物理地址上,文件和目录都是按照”树形“结构组织。如上图所示,这其实就是windows中的文件包含关系。如果我们要找到mp3文件的话,首先知道它的上一层目录是啥,从上图可以知道mp3文件的上一层目录是根目录下的一个子目录。为此,我们需要了解如何读取根目录。

根目录本质上也是一个文件,可它的起始地址在哪里?在FAT32六的分析中,我们可知保留区中包含了数据区内容的信息。其实,根目录的起始地址可以在dbr结构体中存储了根目录的起始簇号。

读取根目录

根目录的起始簇号的内容都是目录项。啥是目录项?目录项里面记载着文件或者目录的信息,它里面包含了:文件名,扩展名,属性,保留区,创建时间,最后访问时间,写时间,数据起始簇号,文件字节大小。这里的属性其实在windows右键打开文件属性显示的内容几乎是一样的。这里文件显示的最大的大小是4B,转换为2的32次幂就是4G的大小,说明最大只能存储4G的文件。

在FAT32中文件与子目录信息都是用目录项来表示.如上图,如果根目录下包含的是一个文件,那么它对应的目录项中的数据起始簇号代表的就是文件数据的起始地址。

如果根目录下包含的内容也是一个目录(子目录),那么根目录下的目录项里的数据起始簇号,代表的就是子目录下的目录项(也就是子目录的信息)

根目录信息提取的代码实现

步骤:

  • 定位根目录位置
  • 添加目录项定义
  • 解析并打印根目录的第一簇

在_xfat_t 结构体中添加簇与根目录的相关信息

/** * xfat结构 */typedef struct _xfat_t     u32_t fat_start_sector;             // FAT表起始扇区    u32_t fat_tbl_nr;                   // FAT表数量    u32_t fat_tbl_sectors;              // 每个FAT表的扇区数    u32_t sec_per_cluster;              // 每簇占用的扇区数    u32_t root_cluster;                 // 根目录的簇号    u32_t cluster_byte_size;            // 每簇字节大小  每个簇字节大小= 簇占用的扇区数*每个扇区的字节大小    u32_t total_sectors;                // 总扇区数    u8_t * fat_buffer;             // FAT表项缓冲    xdisk_part_t * disk_part;           // 对应的分区信息 xfat_t;

获得根目录的fat相关信息

/** * 从dbr中解析出fat相关配置参数 * @param dbr 读取的设备dbr * @return */static xfat_err_t parse_fat_header (xfat_t * xfat, dbr_t * dbr)     xdisk_part_t * xdisk_part = xfat->disk_part;    // 解析DBR参数,解析出有用的参数    xfat->root_cluster = dbr->fat32.BPB_RootClus;   //根目录的起始簇号    xfat->fat_tbl_sectors = dbr->fat32.BPB_FATSz32;    // 如果禁止FAT镜像,只刷新一个FAT表    // disk_part->start_block为该分区的绝对物理扇区号,所以不需要再加上Hidden_sector    if (dbr->fat32.BPB_ExtFlags & (1 << 7))         u32_t table = dbr->fat32.BPB_ExtFlags & 0xF;        xfat->fat_start_sector = dbr->bpb.BPB_RsvdSecCnt + xdisk_part->start_sector + table * xfat->fat_tbl_sectors;        xfat->fat_tbl_nr = 1;     else         xfat->fat_start_sector = dbr->bpb.BPB_RsvdSecCnt + xdisk_part->start_sector;        xfat->fat_tbl_nr = dbr->bpb.BPB_NumFATs;            xfat->sec_per_cluster = dbr->bpb.BPB_SecPerClus; //每簇占用的扇区数    xfat->total_sectors = dbr->bpb.BPB_TotSec32;     // 总的扇区数    xfat->cluster_byte_size = xfat->sec_per_cluster * dbr->bpb.BPB_BytsPerSec; //每个簇占用的字节大小    return FS_ERR_OK;/** * 初始化FAT项 * @param xfat xfat结构 * @param disk_part 分区结构 * @return */xfat_err_t xfat_open(xfat_t * xfat, xdisk_part_t * xdisk_part)     dbr_t * dbr = (dbr_t *)temp_buffer;    xdisk_t * xdisk = xdisk_part->disk;    xfat_err_t err;    xfat->disk_part = xdisk_part;    // 读取dbr参数区    err = xdisk_read_sector(xdisk, (u8_t *) dbr, xdisk_part->start_sector, 1);    if (err < 0)         return err;        // 解析dbr参数中的fat相关信息    err = parse_fat_header(xfat, dbr);    if (err < 0)         return err;        // 先一次性全部读取FAT表: todo: 优化    xfat->fat_buffer = (u8_t *)malloc(xfat->fat_tbl_sectors * xdisk->sector_size);    err = xdisk_read_sector(xdisk, (u8_t *)xfat->fat_buffer, xfat->fat_start_sector, xfat->fat_tbl_sectors);    if (err < 0)         return err;        return FS_ERR_OK;

上面主要关注的代码:

xfat->root_cluster = dbr->fat32.BPB_RootClus; //根目录的起始簇号

xfat->sec_per_cluster = dbr->bpb.BPB_SecPerClus; //每簇占用的扇区数

xfat->cluster_byte_size = xfat->sec_per_cluster * dbr->bpb.BPB_BytsPerSec; //每个簇占用的字节大小

读取根目录对应的簇

如何获得某一个簇的起始地址?

如上图,实际上根目录就存在于簇2中。当然我们设置API不能说仅仅是读取簇2,而且其它簇的地址的起始地址都能读到,为此这里我们假设根目录存在簇4当中。首先要知道簇4的起始地址,那么要知道簇2的起始在哪里。簇2的地址是在保留区获取,前面我为了方便将簇2的起始地址保留到了xfat结构体下的fat_start_sector。

所以簇4的起始地址=((簇4-簇2)*每个簇包含的扇区大小)+簇2的起始地址。 【这里的(簇4-簇2)代表簇号相互减】

#define xfat_get_disk(xfat)  ((xfat)->disk_part->disk) // 获取disk结构/** * 获取指定簇号的第一个扇区编号 * @param xfat xfat结构 * @param cluster_no  簇号 * @return 扇区号 */u32_t cluster_fist_sector(xfat_t *xfat, u32_t cluster_no)    u32_t data_start_sector = xfat->fat_start_sector + xfat->fat_tbl_sectors * xfat->fat_tbl_nr;    return data_start_sector + (cluster_no - 2) * xfat->sec_per_cluster;    // 前两个簇号保留/** * 读取一个簇的内容到指定缓冲区 * @param xfat xfat结构 * @param buffer 数据存储的缓冲区 * @param cluster 读取的起始簇号 * @param count 读取的簇数量 * @return */xfat_err_t read_cluster(xfat_t *xfat, u8_t *buffer, u32_t cluster, u32_t count)   xfat_err_t err = 0;  u32_t i = 0;  u8_t * curr_buffer = buffer;  u32_t curr_sector = cluster_fist_sector(xfat, cluster);  for (i = 0; i < count; i++)         err = xdisk_read_sector(xfat_get_disk(xfat), curr_buffer, curr_sector, xfat->sec_per_cluster);      if (err < 0)                 return err;            curr_buffer += xfat->cluster_byte_size; //读取的簇大小      curr_sector += xfat->sec_per_cluster; //读取的扇区数    return FS_ERR_OK;

err = xdisk_read_sector(xfat_get_disk(xfat), curr_buffer, curr_sector, xfat->sec_per_cluster);

假如根目录存在簇4中,可通过xdisk_read_sector这个API中,【curr_sector = cluster_fist_sector(xfat, cluster)】是要读取的簇4的起始地址,

xfat->sec_per_cluste代表要读取的扇区数

测试

前面提到目录项的内容包括:文件名字,文件创建时间,文件大小等。为此,我们需要定义目录项的结构体,以及目录项的一些宏定义。

#define CLUSTER_INVALID                 0x0FFFFFFF          // 无效的簇号#define DIRITEM_NAME_FREE               0xE5                // 目录项空闲名标记#define DIRITEM_NAME_END                0x00                // 目录项结束名标记#define DIRITEM_ATTR_READ_ONLY          0x01                // 目录项属性:只读#define DIRITEM_ATTR_HIDDEN             0x02                // 目录项属性:隐藏#define DIRITEM_ATTR_SYSTEM             0x04                // 目录项属性:系统类型#define DIRITEM_ATTR_VOLUME_ID          0x08                // 目录项属性:卷id#define DIRITEM_ATTR_DIRECTORY          0x10                // 目录项属性:目录#define DIRITEM_ATTR_ARCHIVE            0x20                // 目录项属性:归档#define DIRITEM_ATTR_LONG_NAME          0x0F                // 目录项属性:长文件名/** * FAT目录项的日期类型 */typedef struct _diritem_date_t     u16_t day : 5;                  // 日    u16_t month : 4;                // 月    u16_t year_from_1980 : 7;       // 年 diritem_date_t;/** * FAT目录项的时间类型 */typedef struct _diritem_time_t     u16_t second_2 : 5;             // 2秒    u16_t minute : 6;               // 分    u16_t hour : 5;                 // 时 diritem_time_t;/** * FAT目录项 */typedef struct _diritem_t     u8_t DIR_Name[8];                   // 文件名    u8_t DIR_ExtName[3];                // 扩展名    u8_t DIR_Attr;                      // 属性    u8_t DIR_NTRes;    u8_t DIR_CrtTimeTeenth;             // 创建时间的毫秒    diritem_time_t DIR_CrtTime;         // 创建时间    diritem_date_t DIR_CrtDate;         // 创建日期    diritem_date_t DIR_LastAccDate;     // 最后访问日期    u16_t DIR_FstClusHI;                // 簇号高16位    diritem_time_t DIR_WrtTime;         // 修改时间    diritem_date_t DIR_WrtDate;         // 修改时期    u16_t DIR_FstClusL0;                // 簇号低16位    u32_t DIR_FileSize;                 // 文件字节大小 diritem_t;

主函数

#include <stdio.h>#include <stdlib.h>#include <string.h>#include "xdisk.h"#include "xfat.h"extern xdisk_driver_t vdisk_driver;const char * disk_path_test = "disk_test.img";const char * disk_path = "disk.img";static u32_t write_buffer[160*1024];static u32_t read_buffer[160*1024];xdisk_t disk;xdisk_part_t disk_part;xfat_t xfat;// io测试,测试通过要注意关掉int disk_io_test (void)   int err;  xdisk_t disk_test;  memset(read_buffer, 0, sizeof(read_buffer));  err = xdisk_open(&disk_test, "vidsk_test", &vdisk_driver, (void *)disk_path_test);  if (err)         printf("open disk failed!\\n");      return -1;    err = xdisk_write_sector(&disk_test, (u8_t *)write_buffer, 0, 2);  if (err)         printf("disk write failed!\\n");      return -1;    err = xdisk_read_sector(&disk_test, (u8_t *)read_buffer, 0, 2);  if (err)         printf("disk read failed!\\n");      return -1;    err = memcmp((u8_t *)read_buffer, (u8_t *)write_buffer, disk_test.sector_size * 2);  if (err != 0)         printf("data no equal!\\n");      return -1;    err = xdisk_close(&disk_test);  if (err)         printf("disk close failed!\\n");      return -1;    printf("disk io test ok!\\n");  return 0;int disk_part_test (void)  u32_t count, i;  xfat_err_t err = FS_ERR_OK;  printf("partition read test...\\n");  err = xdisk_get_part_count(&disk, &count);  if (err < 0)         printf("partion count detect failed!\\n");      return err;    printf("partition count:%d\\n", count);  for (i = 0; i < count; i++)       xdisk_part_t part;    int err;    err = xdisk_get_part(&disk, &part, i);    if (err == -1)           printf("read partion in failed:%d\\n", i);      return -1;            printf("no %d: start: %d, count: %d, capacity:%.0f M\\n",               i, part.start_sector, part.total_sector,               part.total_sector * disk.sector_size / 1024 / 1024.0);    return 0;void show_dir_info (diritem_t * diritem)     char file_name[12];    u8_t attr = diritem->DIR_Attr;    // name    memset(file_name, 0, sizeof(file_name));    memcpy(file_name, diritem->DIR_Name, 11);    if (file_name[0] == 0x05)         file_name[0] = 0xE5;        printf("\\n name: %s, ", file_name);    // attr    printf("\\n\\t");    if (attr & DIRITEM_ATTR_READ_ONLY)         printf("readonly, ");        if (attr & DIRITEM_ATTR_HIDDEN)         printf("hidden, ");        if (attr & DIRITEM_ATTR_SYSTEM)         printf("system, ");        if (attr & DIRITEM_ATTR_DIRECTORY)         printf("directory, ");        if (attr & DIRITEM_ATTR_ARCHIVE)         printf("achinve, ");        // create time    printf("\\n\\tcreate:%d-%d-%d, ", diritem->DIR_CrtDate.year_from_1980 + 1980,            diritem->DIR_CrtDate.month, diritem->DIR_CrtDate.day);    printf("\\n\\time:%d-%d-%d, ", diritem->DIR_CrtTime.hour, diritem->DIR_CrtTime.minute,           diritem->DIR_CrtTime.second_2 * 2 + diritem->DIR_CrtTimeTeenth / 100);    // last write time    printf("\\n\\tlast write:%d-%d-%d, ", diritem->DIR_WrtDate.year_from_1980 + 1980,           diritem->DIR_WrtDate.month, diritem->DIR_WrtDate.day);    printf("\\n\\ttime:%d-%d-%d, ", diritem->DIR_WrtTime.hour,           diritem->DIR_WrtTime.minute, diritem->DIR_WrtTime.second_2 * 2);    // last acc time    printf("\\n\\tlast acc:%d-%d-%d, ", diritem->DIR_LastAccDate.year_from_1980 + 1980,           diritem->DIR_LastAccDate.month, diritem->DIR_LastAccDate.day);    // size    printf("\\n\\tsize %d kB, ", diritem->DIR_FileSize / 1024);    printf("\\n\\tcluster %d, ", (diritem->DIR_FstClusHI << 16) | diritem->DIR_FstClusL0);    printf("\\n");int fat_dir_test(void)     int err;    u32_t curr_cluster;    u8_t * culster_buffer;    int index = 0;    diritem_t * dir_item;    u32_t j;    printf("root dir read test...\\n");    culster_buffer = (u8_t *)malloc(xfat.cluster_byte_size);    // 解析根目录所在的簇    curr_cluster = xfat.root_cluster;    while (is_cluster_valid(curr_cluster))         err = read_cluster(&xfat, culster_buffer, curr_cluster, 1);        if (err)             printf("read cluster %d failed\\n", curr_cluster);            return -1;                dir_item = (diritem_t *)culster_buffer;        for (j = 0; j < xfat.cluster_byte_size / sizeof(diritem_t); j++)             u8_t  * name = (u8_t *)(dir_item[j].DIR_Name);            if (name[0] == DIRITEM_NAME_FREE)                 continue;             else if (name[0] == DIRITEM_NAME_END)                 break;                        index++;            printf("no: %d, ", index);            show_dir_info(&dir_item[j]);                err = get_next_cluster(&xfat, curr_cluster, &curr_cluster);        if (err)             printf("get next cluster failed, current cluster %d\\n", curr_cluster);            return -1;                return 0;int main (void)   xfat_err_t err;  int i;  for (i = 0; i < sizeof(write_buffer) / sizeof(u32_t); i++)         write_buffer[i] = i;    err = xdisk_open(&disk, "vidsk", &vdisk_driver, (void *)disk_path);  if (err)         printf("open disk failed!\\n");      return -1;    err = disk_part_test();  if (err) return err;  err = xdisk_get_part(&disk, &disk_part, 1);  if (err < 0)         printf("read partition info failed!\\n");      return -1;    err = xfat_open(&xfat, &disk_part);  if (err < 0)         return err;    err = fat_dir_test();  if (err) return err;  err = xdisk_close(&disk);  if (err)         printf("disk close failed!\\n");      return -1;    printf("Test End!\\n");  return 0;

主要关注的函数如下

/** * 检查指定簇是否可用,非占用或坏簇 * @param cluster 待检查的簇 * @return */int is_cluster_valid(u32_t cluster)     cluster &= 0x0FFFFFFF;    return (cluster < 0x0FFFFFF0) && (cluster >= 0x2);     // 值是否正确void show_dir_info (diritem_t * diritem)     char file_name[12];    u8_t attr = diritem->DIR_Attr;//获取文件的属性    // 获取文件名或者子目录的名字    memset(file_name, 0, sizeof(file_name));    memcpy(file_name, diritem->DIR_Name, 11);    //FAT32 文档里面规定规范    if (file_name[0] == 0x05)         file_name[0] = 0xE5;        printf("\\n name: %s, ", file_name);    // 文件是否是只读属性    printf("\\n\\t");    if (attr & DIRITEM_ATTR_READ_ONLY)         printf("readonly, ");        //文件是否是隐藏属性    if (attr & DIRITEM_ATTR_HIDDEN)         printf("hidden, ");        //文件是否是系统文件属性    if (attr & DIRITEM_ATTR_SYSTEM)         printf("system, ");          //文件是否为目录    if (attr & DIRITEM_ATTR_DIRECTORY)         printf("directory, ");          //文件是否是归档属性    if (attr & DIRITEM_ATTR_ARCHIVE)         printf("achinve, ");        // 创建 time    printf("\\n\\tcreate:%d-%d-%d, ", diritem->DIR_CrtDate.year_from_1980 + 1980,            diritem->DIR_CrtDate.month, diritem->DIR_CrtDate.day);    printf("\\n\\time:%d-%d-%d, ", diritem->DIR_CrtTime.hour, diritem->DIR_CrtTime.minute,           diritem->DIR_CrtTime.second_2 * 2 + diritem->DIR_CrtTimeTeenth / 100);    // 上一次读取时间    printf("\\n\\tlast write:%d-%d-%d, ", diritem->DIR_WrtDate.year_from_1980 + 1980,           diritem->DIR_WrtDate.month, diritem->DIR_WrtDate.day);    printf("\\n\\ttime:%d-%d-%d, ", diritem->DIR_WrtTime.hour,           diritem->DIR_WrtTime.minute, diritem->DIR_WrtTime.second_2 * 2);    // 上一次访问时间    printf("\\n\\tlast acc:%d-%d-%d, ", diritem->DIR_LastAccDate.year_from_1980 + 1980,           diritem->DIR_LastAccDate.month, diritem->DIR_LastAccDate.day);    // 文件大小    printf("\\n\\tsize %d kB, ", diritem->DIR_FileSize / 1024);    printf("\\n\\tcluster %d, ", (diritem->DIR_FstClusHI << 16) | diritem->DIR_FstClusL0);    printf("\\n");/***********************************************************/int fat_dir_test(void)    int err;    u32_t curr_cluster;    u8_t * culster_buffer;    int index = 0;    diritem_t * dir_item;    u32_t j;    printf("root dir read test...\\n");    //根据保留区中记录的每个簇的字节大小在堆中分配一个数据用于后面的簇读取的信息保存。    culster_buffer = (u8_t *)malloc(xfat.cluster_byte_size);    // 解析根目录所在的簇,其实就是簇2,这里就是读取簇号    curr_cluster = xfat.root_cluster;    // 检查要读取的簇号是否可用    while (is_cluster_valid(curr_cluster))            //读取簇2,将簇号2的一个簇大小的内容        //就是读取簇2的目录项内容存在culster_buffer        err = read_cluster(&xfat, culster_buffer, curr_cluster, 1);        if (err)                     printf("read cluster %d failed\\n", curr_cluster);            return -1;                //将簇2读取的内容转换为目录项结构体        dir_item = (diritem_t *)culster_buffer;        //如何一个一个地读取每一个目录项?        //也很简单就是将整簇大小除以目录项的大小        for (j = 0; j < xfat.cluster_byte_size / sizeof(diritem_t); j++)                     //读取目录项下的文件或者子目录的名字            u8_t  * name = (u8_t *)(dir_item[j].DIR_Name);            if (name[0] == DIRITEM_NAME_FREE)                            continue;             else if (name[0] == DIRITEM_NAME_END)                             break;                        //统计目录项的数量            index++;            printf("no: %d, ", index);            show_dir_info(&dir_item[j]);                err = get_next_cluster(&xfat, curr_cluster, &curr_cluster);        if (err)                     printf("get next cluster failed, current cluster %d\\n", curr_cluster);            return -1;                return 0;

测试


工程代码链接中地址:

github:https://github.com/WOLEN6914183/FAT32.git

百度网盘->码:fat3 https://pan.baidu.com/s/1B8IP61aozYquoDFcKE_J6Q

喜欢就微信扫描下面二维码关注我吧!

相关参考

格式化移动硬盘分配单元大小(如何格式化分区?看懂这篇文章你就学会了)

这篇文章为大家带来如何格式化分区,希望能帮到大家!在这里小编给介绍一种格式化分区工具DiskGenius软件,很多人不知道怎么使用DiskGenius这一款功能强大的工具,事实上DiskGenius使用起来并不难,一样是一键式的操作方式,只...

机械硬盘格式化分配单元大小(怎么选硬盘看参数,光知道所谓的“叠瓦盘”,你还真没入门)

还别不愿意听,真的是维度不同,凭心而论,大家觉得现在一些数码博主的几分钟视频真的可以替代给专业的IT工程师专门设置的几周培训课程有用吗?在短视频横行的时代往往一句“SMR”不能买就能赚取很多流量,很多数码小...

摄像头不录像怎么回事(硬盘录像机备份无法显示问题怎么处理?)

...查询到的录像后,再在电脑上播放时,找不到备份的视频文件,看到提示已经备份成功了,生成了一个文件名,是MP4格式的,但是为什么在WINDOWS的电脑上不能看到这个文件呢?后来经过研究发现,如果硬盘的文件格式为NTFS的,...

怎么弄自己的电子签名(使用Word快捷指令快速输入电子签名的方法)

...手写签名照,将照片插入到word中,把照片调整到合适的大小。2.设置图片格式点击菜单栏的“图片格式”,点击“颜色”,将图片设置为黑白色。再次点击“颜色”的“设置透明色”,然后鼠标点击图片,签名的背景就变为透明...

ntfs和exfat有什么区别

1、指代不同。NTFS:是WindowsNT环境的文件系统。新技术文件系统是WindowsNT家族的限制级专用的文件系统。exFAT:是Microsoft在WindowsEmbeded5.0以上(包括WindowsCE5.0、6.0、WindowsMobile5、6、6.1)中引入的一种适合于闪存的文件系统,为了解...

标准a4文件夹尺寸大小(A4格式的高拍仪是什么?高拍仪能拍多大尺寸的文件?)

近来兴起的办公利器高拍仪,它具备省电、小巧便携、多功能等优势,非常适合固定或移动办公。伴随着无纸化办公的趋势,高拍仪目前被广泛地运用于多个领域。而随着高拍仪的使用场景越来越多,却仍有很多用户对高拍仪的...

指纹打卡机怎么连接电脑打印(考勤机、门禁机如果用U盘导出导入数据)

...门禁终端下载数据至U盘首先准备一个内存小于或等于8G且文件系统为FAT32格式的空U盘注:门禁终端U盘接口一般在机身左侧或下方1、准备U盘并接入门禁终端U盘接口2、数据下载①按菜单键[M/OK]进入门禁终端菜单;②找到[U盘管理]-...

文件加(「科普」文件与文件夹的区别是什么)

...在计算机系统中的一段数据,它们有着自己的文件类型和大小。比如说,文档文件可以是Word文档或者PDF文档,图像文件可以是JPG或者PNG格式,视频文件可以是AVI或者MP4格式,而音乐文件可以是WAV或者MP3格式。文件的大小取决于...

格式化以后还能恢复吗(sd卡不小心格式化能恢复吗?)

...目前主流的存储设备之一。在使用的时候,多数人都认为格式化之后就不能恢复了,那么SD卡格式化之后能怎么恢复呢?本文就来分享下这个内容,感兴趣的可以往下看看哦。首先,我们需要了解下什么是格式化:格式化是指对...

淝水之战的特点(人教历史七年级上册第4单元 三国两晋南北朝时期预习要点)

第四单元三国两晋南北朝时期:政权分立与民族交融第16课三国鼎立三国鼎立的背景:东汉末年,各地出现许多割据一方的军阀,他们彼此长期混战,生产遭到严重破坏。一、官渡之战1、背景:东汉末年,军阀割据。2、概况:...