Gorgon_Meducer 发表于 2008-9-24 16:43:03

[开源][交流]如何读写FAT32文件系统(9-24-2008 Updated)

本帖最后由 Gorgon_Meducer 于 2012-8-1 21:23 编辑

>>写在前面的话
有待添加内容

[专题索引]
    >> 磁盘引导扇区与磁盘分区表          ——如何从硬盘(U盘)中找到我们需要的分区    1楼
    >> BIOS Parameter Block 与 FAT类型   ——如何区分FAT12、FAT16和FAT32            2楼
    >> 磁盘分区逻辑扇区的读取            ——如何以逻辑扇区编号来访问实际的物理扇区   3楼
    >> FAT32目录的访问                   ——如何从指定的目录中找到想要的文件         4楼
    >> 文件的存放结构                  ——如何读写指定的文件                     5楼

[参考文献]
    A、硬盘物理结构和FAT文件系统解析(一)
    B、硬盘物理结构和FAT文件系统解析(二)

[相关下载]
    A、FAT32文件系统白皮书(E文原版)
    B、硬盘物理结构和FAT文件系统解析ourdev_486205.pdf(文件大小:970K)

[更新日至]
    更新第一章、第二章、第三章、第四章、第五章的核心代码和实例。具体讲解部
               分有待补充。

Gorgon_Meducer 发表于 2008-9-24 16:43:12

本帖最后由 Gorgon_Meducer 于 2012-8-1 22:24 编辑

[磁盘引导扇区与磁盘分区表]    ——如何从硬盘(U盘)中找到我们需要的分区

[原理解析]

[数据结构]
/*------------------*
*   常 数 宏 定 义*
*------------------*/
# define DPT_START_ADDRESS      0x01BE

/*------------------*
*   动 作 宏 定 义*
*------------------*/
# define DPT_PARTITION_START_SECTOR(__DPT_ITEM_ADDR)    \
            (__DPT_ITEM_ADDR)->RelativeSectors

/********************
*用户变量类型定义 *
********************/
typedef struct DiskPartitionTableItem DPT_ITEM;

/********************
*    结构体定义区   *
********************/
struct DiskPartitionTableItem
{
    BYTE      ActivePartition;
    BYTE      StartHead;
    unsigned    StartSector   :6;
    unsigned    StartCylinder   :10;
    BYTE      OSIndicator;
    BYTE      EndHead;
    unsigned    EndSector       :6;
    unsigned    EndCylinder   :10;
    UINT32      RelativeSectors;
    UINT32      TotalSectors;
};
[关键代码]
>>如何依次获取各个磁盘分区的信息
/***********************************************************
*   函数说明:获取下一个DPT项                            *
*   输入:      主引导扇区指针,分区表项指针               *
*   输出:      下一个分区表项                           *
*   调用函数:无                                       *
* -------------------------------------------------------- *
*   [使用说明]                                             *
*         当传入的分区表项指针为空(NULL)时,自动返回第 *
*       一个分区表项。当传入的分区表项指针不为空时,自动返 *
*       回下一个分区表项的指针,当下一个分区表项不存在时, *
*       返回空(NULL)                                     *
***********************************************************/
DPT_ITEM *Get_Next_Disk_Partition
    (
      BYTE *pchMasterBootSector,
      DPT_ITEM *pdptPartition
    )
{
    if (pchMasterBootSector == NULL)
    {
      /* 无效的输入 */
      return NULL;
    }   
   
    if (pdptPartition == NULL)
    {
      /* 要求返回第一个分区表项 */
      pdptPartition = (DPT_ITEM *)(pchMasterBootSector + DPT_START_ADDRESS);
    }
    else
    {
      /* 指向下一个分区表项 */
      pdptPartition += 1;
    }
   
    /* 进行分区表项的有效性检测 */
    {
      UINT8 n = 0;
      BOOL bIfValid = FALSE;
      for (n = 0;n < sizeof(DPT_ITEM);n++)
      {
            if (((BYTE *)pdptPartition) != 0x00)
            {
                bIfValid = TRUE;
                break;
            }
      }
      if (!bIfValid)
      {
            /* 表项为空 */
            return NULL;
      }
    }
   
    return pdptPartition;
}
[使用范例]
Example A:
//从引导扇区中提取第一个磁盘分区在物理扇区中的偏移量
//其中g_chSectorBuffer是一个大小为512字节的数组,保存
//了磁盘第一个引导扇区的内容
s_dwPartitionSectorOffset = DPT_PARTITION_START_SECTOR
            (
                Get_Next_Disk_Partition(g_chSectorBuffer,NULL)
            );

Example B:

//从引导扇区中查找第一个类型为NTFS的磁盘分区,并返回
//它在物理扇区偏移量

# define OS_INDICATOR_NTFS                0x07

DPT_ITEM *pDPTItem = NULL;

do
{
    //读取新的分区信息
    pDPTItem = Get_Next_Disk_Partition(g_chSectorBuffer,pDPTItem);
   
    if ((pDPTItem != NULL) && (pDPTItem->OSIndicator == OS_INDICATOR_NTFS))
    {
      s_dwPartitionSectorOffset =DPT_PARTITION_START_SECTOR(pDPTItem);
      break;
    }
}
while(pDPTItem != NULL)

if (pDPTItem != NULL)
{
    //找到了需要的分区,进行对应的处理
}
else
{
    //没有找到需要的分区,进行对应的处理
}

Gorgon_Meducer 发表于 2008-9-24 16:43:28

本帖最后由 Gorgon_Meducer 于 2012-8-1 22:20 编辑

    ——如何区分FAT12、FAT16和FAT32

<font color=blue>[原理解析]/*---------------------------------------------------------*
*[保留扇区] |启动扇区                                  *
*Reserved   |FSINFO                                    *
*Sectors    |Root区备份(SECTOR 6)                  *
* -------------------------------------------------------- *
*    |FAT表0                                    *
*             |FAT表1                                    *
*             |...    (BPB_NumFATs)                      *
* -------------------------------------------------------- *
*|FAT16/12的根目录,FAT32不存在这个区域   *
* -------------------------------------------------------- *
*[ 数据区 ] |FAT32的根目录和数据。                     *
*             |需要说明的是,以第一个数据扇区为起始,簇*
*             |从2开始编号。                           *
*---------------------------------------------------------*/


[数据结构]
/*------------------*
*   常 数 宏 定 义*
*------------------*/
# define FAT_TYPE_FAT32             0x00
# define FAT_TYPE_FAT16             0x01
# define FAT_TYPE_FAT12             0x02
# define FAT_ERROR                  0xFF

/********************
*用户变量类型定义 *
********************/
typedef struct BiosParameterBlock   FAT_BPB;

/********************
*    结构体定义区   *
********************/
struct BiosParameterBlock
{
    /* FAT32 Structure Starting at Offset 11 */
    UINT16BPB_BytePerSec;         //每扇区的字节数通常为512
    UINT8   BPB_SecPerClus;         //每簇的扇区数量
    UINT16BPB_ResvdSecCnt;      //保留扇区数
    UINT8   BPB_NumFATs;            //FAT表的数量
    UINT16BPB_RootEntCnt;         //FAT12/16根目录中目录项的项数,FAT32为0
    UINT16BPB_TotSec16;         //FAT12/16系统记录卷标中扇区的总数,FAT32为0
    UINT8   BPB_Media;            //磁盘介质
    UINT16BPB_FATSz16;            //FAT12/16用于保存一个FAT标所占用的扇区数
    UINT16BPB_SecPerTrk;          //每磁道的扇区数
    UINT16BPB_NumHeads;         //磁头数
    UINT32BPB_HiddSec;            //隐藏扇区
    UINT32BPB_TotSec32;         //FAT32卷中扇区的总数目
   
    /* FAT32 Structure Starting at Offset 36 */
    UINT32BPB_FATSz32;            //一个FAT32表中占用的扇区数
    UINT16BPB_ExtFlag;            //标志位
    UINT16BPB_FSVer;            //FAT32 version
    UINT32BPB_RootClus;         //FAT32 根目录所在簇
    UINT16BPB_FSInfo;             //FSINFO结构体在保留扇区内的扇区号
    UINT16BPB_BkBootSec;          //Boot 记录的备份在保留区内的扇区号,通常为6
    BYTE    BPB_Reserved;       //RESERVED
};
[关键代码]
>>如何判断当前的FAT文件系统类型
/*------------------*
*   动 作 宏 定 义*
*------------------*/
/* 获取根目录所占用的扇区数 */
# define GET_ROOT_DIR_SECTOR_COUNT(__BPB)   \
            (((__BPB).BPB_RootEntCnt * 32 + ((__BPB).BPB_BytePerSec - 1)) / (__BPB).BPB_BytePerSec)

/* 获取FAT32文件系统中第一个数据扇区的编号(位于簇2)*/
# define GET_FAT_FIRST_DATA_SECTOR(__BPB) \
            (\
                (__BPB).BPB_ResvdSecCnt + (__BPB).BPB_NumFATs * \
                (\
                  ((__BPB).BPB_FATSz16 != 0) ?\
                  (__BPB).BPB_FATSz16 : (__BPB).BPB_FATSz32\
                ) + GET_ROOT_DIR_SECTOR_COUNT(__BPB)\
            )

/***********************************************************
*   函数说明:获取当前FAT的类型                        *
*   输入:      FAT_BPB指针                              *
*   输出:      FAT类型                                    *
*   调用函数:无                                       *
***********************************************************/
UINT8 Get_FAT_Type(FAT_BPB *pFATBPB)
{
    if (pFATBPB == NULL)
    {
      return FAT_ERROR;
    }
   
    {
      UINT32 dwTotalSectors;
      if (pFATBPB->BPB_TotSec16 != 0)
      {
            dwTotalSectors = pFATBPB->BPB_TotSec16;
      }
      else
      {
            dwTotalSectors = pFATBPB->BPB_TotSec32;
      }
      dwTotalSectors -= GET_FAT_FIRST_DATA_SECTOR((*pFATBPB));

      dwTotalSectors /= pFATBPB->BPB_SecPerClus;
      
      if (dwTotalSectors &lt; 4085)
      {
            return FAT_TYPE_FAT12;
      }
      else if (dwTotalSectors &lt; 65525)
      {
            return FAT_TYPE_FAT16;
      }
    }
    return FAT_TYPE_FAT32;
}
[使用范例]
Example A:
//判断当前的文件类型是否为FAT32,其中g_chBPBBuffer是一个
//大小为512字节的缓冲区,保存了BPB结构所在的扇区,也就是
//对应磁盘分区的逻辑0扇区中的内容。由于BPB在该扇区中的起
//始偏移为11,所以我们在需要访问BPB时需要加入相应的偏移
//量。
if (Get_FAT_Type((FAT_BPB *)(g_chBPBBuffer + 11)) != FAT_TYPE_FAT32)
{
    /* 检测FAT类型是否符合要求 */
    return FALSE;
]

Gorgon_Meducer 发表于 2008-9-24 16:43:35

本帖最后由 Gorgon_Meducer 于 2012-8-1 22:15 编辑

[磁盘分区逻辑扇区的读取]    ——如何以逻辑扇区编号来访问实际的物理扇区
    根据前面的叙述,我们知道,一个物理存储介质中可能有若干个磁盘分区,这些
磁盘分区的逻辑0扇区相对介质的物理0扇区来说,都有一个偏移量。如何在编写文件
系统的代码时,能够以磁盘分区的逻辑扇区编号来访问设备,而无需一一指名访问时
具体的物理扇区地址呢?
    解决方法很简单:所有的文件系统代码在编写时,都以磁盘分区的逻辑扇区地址
为依据,也就是相对BPB所在的扇区为逻辑0扇区,然后所有针对设备的扇区读写函数
都通过一个统一的函数接口来实现,而该接口函数实际上会针对逻辑扇区的地址进行
物理地址的偏移运算,从而根据逻辑地址得到实际的物理扇区地址。

[关键代码]
//定义逻辑扇区访问接口
# define GET_SECTOR(__SECTOR_NUMBER,__BUFF_ADDR) \
            Get_Sector((__SECTOR_NUMBER),(__BUFF_ADDR))//我们假设这是一个U盘设备,host_read_10_ram()会利用SCSI函数的READ_10指令读取
//U盘的指定物理扇区/***********************************************************
*   函数说明:扇区读取接口函数                           *
*   输入:      要读取的扇区编号,存放扇区的缓冲区         *
*   输出:      操作是否成功                               *
*   调用函数:host_read_10_ram()                         *
***********************************************************/
BOOL Get_Sector(UINT32 dwSectorNumber,BYTE *pBuffer)
{
    if (pBuffer == NULL)
    {
      return FALSE;
    }
   
    host_read_10_ram
      (
            //还记得这个变量s_dwPartitionSectorOffset是怎么获得的么?
            dwSectorNumber + s_dwPartitionSectorOffset,   
            pBuffer
      );

    return TRUE;
}[使用范例]
Example A:
//通过接口函数读取该逻辑分区的0扇区,
// 0 为逻辑扇区地址
// g_chSectorBuffer是扇区缓冲区
if (!GET_SECTOR(0,g_chSectorBuffer))
{
    //扇区读取失败的处理
}

Gorgon_Meducer 发表于 2008-9-24 16:45:52

本帖最后由 Gorgon_Meducer 于 2012-8-1 21:56 编辑

    ——如何从指定的目录中找到想要的文件

[原理解析]

[数据结构]
/*------------------*
*   常 数 宏 定 义*
*------------------*/
# define ATTR_READ_ONLY         0x01
# define ATTR_HIDDEN            0x02
# define ATTR_SYSTEM            0x04
# define ATTR_VOLUME_ID         0x08
# define ATTR_DIRECTORY         0x10
# define ATTR_ARCHIVE         0x20
# define ATTR_LONG_NAME         (ATTR_READ_ONLY |\
                              ATTR_HIDDEN |   \
                              ATTR_SYSTEM |   \
                              ATTR_VOLUME_ID)

# define FAT_ITEM_UNLOCATED         0x00000000
# define FAT_ITEM_LOCATED_LBOUND    0x00000002
# define FAT_ITEM_LOCATED_UBOUND    0xFFFFFFEF
# define FAT_ITEM_RESERVED_LBOUND   0xFFFFFFF0
# define FAT_ITEM_RESERVED_UBOUND   0xFFFFFFF6
# define FAT_ITEM_BAD_CLUSTER       0xFFFFFFF7
# define FAT_ITEM_EOC_LBOUND      0xFFFFFFF8
# define FAT_ITEM_EOC_UBOUND      0xFFFFFFFF

/*------------------*
*   动 作 宏 定 义*
*------------------*/
/* 计算出指定簇的第一个扇区的编号 */
# define GET_FIRST_SECTOR_OF_CLUSTER(__BPB,__CLUSTER) \
            (((__CLUSTER) - 2) * (__BPB).BPB_SecPerClus + GET_FAT_FIRST_DATA_SECTOR(__BPB))

/********************
*用户变量类型定义 *
********************/
typedef struct FAT32DirectoryEntryFAT32_DIR_ENTRY;

/********************
*    结构体定义区   *
********************/
struct FAT32DirectoryEntry
{
    BYTE    DIR_Name;
    UINT8   DIR_Attr;
    UINT8   DIR_NTRes;
    UINT8   DIR_CrtTimeTenth;
    UINT16DIR_CrtTime;
    UINT16DIR_CrtDate;
    UINT16DIR_LstAccDate;
    UINT16DIR_FstClusHI;
    UINT16DIR_WrtTime;
    UINT16DIR_WrtDate;
    UINT16DIR_FstClusLO;
    UINT32DIR_FileSize;
};
[关键代码]
>>如何从目录中获取指定编号的条目信息
/***********************************************************
*   函数说明:返回指定目录项数据                         *
*   输入:      BPB,目录项索引,保存目录项的缓冲区指针    *
*   输出:      保存目录项的缓冲区指针                     *
*   调用函数:无                                       *
***********************************************************/
FAT32_DIR_ENTRY *Get_Directory_Entry_Item
      (
            FAT_BPB *pFATBPB,
            UINT32 dwCluster,
            UINT32 dwIndex,
            BYTE *pchBuffer
      )
{
    if (
            (pFATBPB == NULL)
      ||(pchBuffer == NULL)
      ||(
                (dwCluster &lt; FAT_ITEM_LOCATED_LBOUND)
            &&(dwCluster> FAT_ITEM_LOCATED_UBOUND)
            )
       )
    {
      /* 无效的输入 */
      return NULL;
    }
   
    {
      /* 获取根目录所在的扇区 */
      BYTE   chSectorBuffer;
      UINT32 dwDirectoryStartSector;
      UINT16 wItemsPerSector;
      dwDirectoryStartSector = GET_FIRST_SECTOR_OF_CLUSTER((*pFATBPB),dwCluster);
      wItemsPerSector = pFATBPB->BPB_BytePerSec / sizeof(FAT32_DIR_ENTRY);

      if (
            !GET_SECTOR
                (
                  dwDirectoryStartSector + (dwIndex / wItemsPerSector),
                  chSectorBuffer
                )
         )
      {
            /* 读取错误 */
            
            return NULL;
      }

      (*(FAT32_DIR_ENTRY *)pchBuffer) =
                ((FAT32_DIR_ENTRY *)chSectorBuffer);
    }
   
    /* 返回结果 */
    return (FAT32_DIR_ENTRY *)pchBuffer;
}
>>如何从目录指定的位置开始查找指定扩展名的文件
/***********************************************************
*   函数说明:从FAT32表中查找指定扩展名称的文件          *
*   输入:      BPB指针,扩展名字符串,上一个有效目录入口*
*   输出:      是否找到需要的文件                         *
*   调用函数:无                                       *
* -------------------------------------------------------- *
*   [使用说明]                                             *
*         输入的扩展名指针可以为空,这将导致直接从指定位 *
*       置开始向后进行遍历输出。当上一次的目录入口地址输入 *
*       为空时,则表示输出一个符合要求的结果。当找不到符合 *
*       要求的结果时,输出为NULL。                         *
***********************************************************/
BOOL Find_File_Extend_Name
      (
            FAT_BPB *pFATBPB,
            UINT32 dwCluster,
            BYTE *pstrFileExterndName,
            UINT32 *pdwLastEntry,
            FAT32_DIR_ENTRY *pDIREntryResult
      )
{
    UINT32 dwSearchPoint = 0;
    if (
            (pFATBPB == NULL)
      ||(
                (pdwLastEntry == NULL)
            &&(pDIREntryResult == NULL)
            )
       )
    {
      /* 无效的输入 */
      return FALSE;
    }
   
    if (pdwLastEntry == NULL)
    {
      dwSearchPoint = 0;
    }
    else
    {
      dwSearchPoint = *pdwLastEntry;
    }
   
    while(TRUE)
    {
      BYTE chDIREntryBuffer;
      /* 获取指定的目录入口 */
      FAT32_DIR_ENTRY *pDIREntry = Get_Directory_Entry_Item
                (
                  pFATBPB,
                  dwCluster,
                  dwSearchPoint,
                  chDIREntryBuffer
                );
      if (pDIREntry == NULL)
      {
            /* 读取目录项失败 */
            return FALSE;
      }
      
      /* 检测目录项是否有效 */
      if (pDIREntry->DIR_Name == 0x00)
      {
            /* 已经是目录项的最后内容了 */
            break;
      }
      else if (
                  (pDIREntry->DIR_Name == 0xE5)
                ||((pDIREntry->DIR_Attr & ATTR_LONG_NAME) == ATTR_LONG_NAME)
                ||((pDIREntry->DIR_Attr & ATTR_DIRECTORY) == ATTR_DIRECTORY)
                )
      {
            /* 该目录项为空项 */
            dwSearchPoint++;
            continue;
      }
      
      dwSearchPoint++;
      
      if (
                pDIREntry->DIR_Name == pstrFileExterndName
            &&pDIREntry->DIR_Name == pstrFileExterndName
            &&pDIREntry->DIR_Name == pstrFileExterndName
         )
      {
            /* 扩展名匹配 */
            
            if (pdwLastEntry != NULL)
            {
                *pdwLastEntry = dwSearchPoint;
            }
            
            if (pDIREntryResult)
            {
                (*pDIREntryResult) = (*pDIREntry);
            }
            return TRUE;
      }
    }
   
    return FALSE;
}
[使用范例]
Example A:
//列出根目录下所有的TXT文件名
//g_chBPBBuffer里面保存的是0扇区中的内容
UINT32 dwLastEntry = 0;
FAT32_DIR_ENTRY Entry = {0};
               
while(Find_File_Extend_Name
    (
      (FAT_BPB *)(g_chBPBBuffer + 11),
         2,
         "TXT",
         &dwLastEntry,
         &Entry
   ))
{
    UINT8 n = 0;
    UINT8 *pchName = Entry.DIR_Name;
   
    for (n = 0;n &lt; 11;n++)
    {
      while(!SERIAL_OUT(pchName));
    }
    //通过串口输出回车换行符浩
    while(!SERIAL_OUT(10));
    while(!SERIAL_OUT(13));
}

Gorgon_Meducer 发表于 2008-9-24 16:45:59

本帖最后由 Gorgon_Meducer 于 2012-8-1 21:52 编辑

[文件的存放结构]    ——如何读写指定的文件



<font color=blue>[原理解析]



[数据结构]



[关键代码]

>>如何从文件的簇链中获取当前簇的后续簇
/***********************************************************
*   函数说明:获取当前簇的下一个簇                     *
*   输入:      BPB缓冲,当前簇号                        *
*   输出:      下一个簇号                                 *
*   调用函数:无                                       *
***********************************************************/
static UINT32 Get_Next_Cluster(FAT_BPB *pFATBPB,UINT32 dwCluster)
{
    UINT32 dwSectorNumber;
    UINT16 wByteOffset;
    BYTE   chSectorBuffer;
   
    dwSectorNumber = pFATBPB->BPB_ResvdSecCnt +
                ((dwCluster * 4) / (pFATBPB->BPB_BytePerSec));
    wByteOffset = (dwCluster * 4) % (pFATBPB->BPB_BytePerSec);

    /* 读取指定的扇区 */
    if (!GET_SECTOR(dwSectorNumber,chSectorBuffer))
    {
      /* 读取错误 */
      return FAT_ITEM_BAD_CLUSTER;
    }
   
    /* 获取下一个簇的簇号 */
    return TYPE_CONVERSION
            (
                &chSectorBuffer,
                UINT32
            );
}
>>如何根据获取的目录项信息顺序的读取到指定的文件内容
/***********************************************************
*   函数说明:从指定的文件里面顺序读取一个扇区的数据   *
*   输入:      BPB指针,文件入口地址,读写指针,          *
*               存放数据的缓冲区                           *
*   输出:      读取数据区的实际大小                     *
*   调用函数:Get_Next_Cluster()                         *
* -------------------------------------------------------- *
*   [使用说明]                                             *
*         当开始一个新文件的读取时,需要通过pReadPoint将 *
*       一个0扇区编号传递给函数;其余时候,传递任何数值都*
*       将被无视,函数通过指针pReadPoint告知外部当前的读写 *
*       位置。                                             *
***********************************************************/
BOOL Read_File_Sectors
      (
            FAT_BPB *pFATBPB,
            FAT32_DIR_ENTRY *pFileEntry,
            UINT32 *pReadPoint,
            BYTE *pchBuffer,
            UINT16 *pwSize
      )
{
    static UINT32 s_dwReadPoint = 0;
    static UINT32 s_dwRemainFileSize = 0;
    static UINT32 s_dwReadCluster = 0;
    static UINT8s_chInClusterSectorCounter = 0;
    UINT32 dwSector = 0;
    UINT16 wTempSize = 0;
    if(
            (pFATBPB == NULL)
      ||(pFileEntry == NULL)
      ||(pReadPoint == NULL)
      ||(pchBuffer == NULL)
      )
    {
      /* 无效的输入 */
      return FALSE;
    }
   
    //新文件初始化
    if ((*pReadPoint) == 0)
    {
      s_dwReadPoint = 0;                                  //初始化读写指针
      s_chInClusterSectorCounter = 0;
      s_dwRemainFileSize = pFileEntry->DIR_FileSize;      //初始化剩余文件大小
      //获取文件的起始簇号
      s_dwReadCluster = ((UINT32)(pFileEntry->DIR_FstClusHI) &lt;&lt; 16)
                        | (UINT32)(pFileEntry->DIR_FstClusLO);
    }
   
    //检查簇的合法有效性
    if(
            (s_dwReadCluster>= FAT_ITEM_EOC_LBOUND)
      &&(s_dwReadCluster &lt;= FAT_ITEM_EOC_UBOUND)
      )
    {
      if (s_dwRemainFileSize == 0)
      {
            //正常结束
            if (pwSize != NULL)
            {
                *pwSize = 0;
            }
            return TRUE;
      }
      else
      {
            //非正常结束
            return FALSE;
      }
    }
    else if (!(
                (s_dwReadCluster>= FAT_ITEM_LOCATED_LBOUND)
            &&(s_dwReadCluster &lt;= FAT_ITEM_LOCATED_UBOUND)
            ))
    {
      //错误的簇信息
      return FALSE;
    }
   
    if (s_dwRemainFileSize == 0)
    {
      //文件读写完毕
      if (pwSize != NULL)
      {
            *pwSize = 0;
      }
      return TRUE;
    }
   
    //获取当前正在读取的簇的首扇区编号
    dwSector = GET_FIRST_SECTOR_OF_CLUSTER(*pFATBPB,s_dwReadCluster)
                + s_chInClusterSectorCounter;

    //读取扇区数据
    if (!GET_SECTOR(dwSector,pchBuffer))
    {
      /* 读取错误 */
      return FALSE;
    }
   
    //更新读写指针
    s_dwReadPoint++;
    s_chInClusterSectorCounter++;
    if (s_chInClusterSectorCounter == pFATBPB->BPB_SecPerClus)
    {
      // 完成了一个簇的读取
      s_chInClusterSectorCounter = 0;                     //复位簇内扇区读写指针
      s_dwReadCluster = Get_Next_Cluster                  //获取下一个簇
                            (
                              pFATBPB,
                              s_dwReadCluster
                            );
    }
   
    // 返回当前的读写位置
    (*pReadPoint) = s_dwReadPoint;
    // 返回实际读取到的字节数
    wTempSize = (s_dwRemainFileSize>= pFATBPB->BPB_BytePerSec) ?
                pFATBPB->BPB_BytePerSec :
                s_dwRemainFileSize;
    if (pwSize != NULL)
    {
      *pwSize = wTempSize;
    }
   
    /* 更新完成当前读写前的剩余大小 */
    s_dwRemainFileSize -= wTempSize;
                  
    return TRUE;
}
[使用范例]
Example A:
//显示根目录下所有TXT文件的文件名及文件内容
UINT32 dwLastEntry = 0;
UINT32 dwReadPoint = 0;
BYTE chBuffer;
UINT16 wSize = 0;
BYTE chBuffer;
FAT32_DIR_ENTRY Entry = {0};
               
while(Find_File_Extend_Name
    (
      (FAT_BPB *)(g_chBPBBuffer + 11),
      2,
      "TXT",
      &dwLastEntry,
      &Entry
   ))
{
    UINT8 n = 0;
    UINT8 *pchName = Entry.DIR_Name;

    for (n = 0;n &lt; 11;n++)
    {
      while(!SERIAL_OUT(pchName));
    }
    while(!SERIAL_OUT(10));
    while(!SERIAL_OUT(13));

    dwReadPoint = 0;
    while(Read_File_Sectors
            (
                (FAT_BPB *)(g_chBPBBuffer + 11),
                &Entry,
                &dwReadPoint,
                chBuffer,
                &wSize
             ))
    {
      BYTE *p = chBuffer;
      if (wSize == 0)
      {
            break;
      }
      while(wSize--)
      {
            while(!SERIAL_OUT(*p))
            {
                PROC_Serial_Transmitter();
            }
            PROC_Serial_Transmitter();
            p++;
      }
    }
    while(!SERIAL_OUT(10));
    while(!SERIAL_OUT(13));

}

Gorgon_Meducer 发表于 2008-9-24 16:46:21

</font>&lt;有待添加内容>

Gorgon_Meducer 发表于 2008-9-24 16:46:34

</font>&lt;有待添加内容>

wanyou132 发表于 2008-9-24 18:26:30

哦哦哦

精品啊,重点学习

佩服&nbsp;傻孩子&nbsp;

ifree64 发表于 2008-9-24 21:48:56

沉得真快啊,帮顶一下

kalo 发表于 2008-9-24 23:42:55

顶!

傻孩子帖子的排版没得说!

cgbabc 发表于 2008-9-24 23:44:15

好贴子一定要顶的,呵呵

hn_ny_dxs 发表于 2008-9-24 23:51:35

很详细,谢谢!



前段时间我想写读取硬盘逻辑扇区的程序,发帖问了没人回答。不过我已经把程序写好了,现在的FAT程序支持1主分区+5逻辑分区的磁盘文件搜索和读取,对于137G内的硬盘来说,已达到实用阶段^_^

testcode 发表于 2008-9-25 00:16:16

huanxian 发表于 2008-9-25 00:20:35

顶&nbsp;顶&nbsp;

kebaojun305 发表于 2008-12-14 15:06:02

我以来收藏。

steven 发表于 2008-12-14 15:47:27

好东西,顶一顶!

zhaojun_xf 发表于 2008-12-19 08:05:55

学习

fsclub 发表于 2008-12-19 08:24:42

最后能来个完整例子,比如用AVR写个TXT文件到SD中,就完美了.

bbgaocumt 发表于 2008-12-23 23:40:10

牛逼

learntech 发表于 2008-12-24 08:34:34

mark

yzlyear 发表于 2008-12-24 11:39:11

不错,记号

bestmomo 发表于 2008-12-24 16:23:36

好贴&nbsp;记号

525133174 发表于 2008-12-29 13:44:25

先做个记号,毕业设计要做用ARM9实现这个功能

要细细研究~~~

djl310 发表于 2009-1-15 20:14:01

mark

hibond 发表于 2009-3-5 13:45:54

mark

KANGYD 发表于 2009-3-5 19:56:24

好长啊!LZ厉害

pldjn 发表于 2009-3-5 20:11:45

关于FAT系统,MARK

valley 发表于 2009-3-9 17:31:42

1K SRAM 的单片机玩不转这个啊。

Gorgon_Meducer 发表于 2009-3-9 20:21:03

恩,1K Sram基本不用考虑FAT系统……非要在1K SRAM的系统上跑……我只能说
很具有表演性……

shenwuzhe 发表于 2009-3-10 09:11:47

mark

hansur 发表于 2009-4-7 15:16:39

好贴,关于文件系统

fy024 发表于 2009-4-7 23:07:19

发现自己就是个 超级菜鸟啊!!!

valley 发表于 2009-4-10 17:35:17

MBR扇区的字节数是不是一定是512Bytes的?可否扩展为其它的数值?
因为我看fat手册里面是可以规定扇区字节数的,手册里面的扇区是否只是局限于该分区范围内呢?
各种资料看多了有点混乱-_- thanks.

shouwangzhe 发表于 2009-4-12 21:23:01

厉害!

valley 发表于 2009-4-13 09:21:57

晕啊,怎么我看1、2楼,3、4楼,5、6楼,7,8楼的内容都是重复的?
是不是重复发了?

Gorgon_Meducer 发表于 2009-4-13 15:23:38

网站被攻击的时候,数据恢复导致的错误。别介意。

valley 发表于 2009-4-13 21:59:19

没介意,哈哈。

麻烦看一下40楼的问题,谢谢。

据说硬盘的一个扇区将来可能扩展到4kbytes,不知要怎样保证和现有硬盘的兼容性呢?

Gorgon_Meducer 发表于 2009-4-13 23:39:09

写代码的时候老老实实根据扇区大小来设置参数,而不是以默认的512字节来操作扇区就可以了。
扇区的大小应该根据BPB的内容来获取。

valley 发表于 2009-4-14 01:03:32

多谢指教。
不过BPB是VFAT FS里面才有的东西,
而我的意思是MBS(也即0柱面0磁头第一个扇区里面)是否一定是512bytes?
如果不是的话,从哪里可以得到该参数?

abyass 发表于 2009-4-14 11:10:49

好资料,顶

lisuweizhai 发表于 2009-4-14 14:12:56

好帖!

lisuweizhai 发表于 2009-4-14 14:13:00

好帖!

lisuweizhai 发表于 2009-4-14 14:13:24

好帖!

valley 发表于 2009-4-14 14:34:58

烦人啊,还有结构体的字节对齐问题。

Adrian 发表于 2009-4-23 20:09:15

顶    LZ强人

Gorgon_Meducer 发表于 2009-4-24 09:14:07

to 【46楼】 valley 微风山谷
    准确的说法是这样的:在总共512byte的主引导记录中,MBR的引导程序占了其中的前446个字
节(偏移0H~偏移1BDH),随后的64个字节(偏移1BEH~偏移1FDH)为DPT(Disk PartitionTable,硬盘
分区表),最后的两个字节“55 AA”(偏移1FEH~偏移1FFH)是分区有效结束标志。

naohbbq 发表于 2009-5-24 00:53:42

记号,随时关注进展

jtyytj 发表于 2009-6-16 11:03:18

好厉害呀!
请教一个问题:我有一个台电酷闪 4G U盘,用单片机分别读取 0、1、2、3、4、5扇区(512B)时,全为零,直到第6扇区时才读到非零值,而读取爱国者(aigo 4G)正常,可以读到 0 扇区的BPB记录。用WinHEX软件读这两种 U 盘的时候都正常。是不是我没有弄清楚台电酷闪 BPB存放的正确位置,或者是物理扇区和逻辑扇区的区别?

Gorgon_Meducer 发表于 2009-6-16 11:54:26

按道理来说BPB应该是在0扇区的……

wwuchang 发表于 2009-6-16 12:19:04

mark一下。有时间的时候看看那。

wuyou 发表于 2009-6-18 22:07:10

顶一个!

cowboy 发表于 2009-6-18 23:51:56

mark

sange 发表于 2009-6-25 21:05:21

做个记号,回头重点学习。

dingdangCat 发表于 2009-6-25 21:46:24

纯mark

hsztc 发表于 2009-6-26 00:51:48

等能看懂的时候来看...

sinbord 发表于 2009-7-24 15:11:34

顶!~mark!

hassim 发表于 2009-7-24 16:20:14

好资料,精品

liangbmw 发表于 2009-7-24 16:53:46

mark

dengxiaofeng 发表于 2009-7-24 20:42:15

浏览过了,不错,保存下来,好好看看!

chengpiaopiao 发表于 2009-11-1 00:03:59

mark

ksniper 发表于 2009-11-1 16:05:04

傻孩子的好帖

li20030505 发表于 2009-11-9 13:43:51

MARK

heng123 发表于 2009-11-21 22:36:32

A、硬盘物理结构和FAT文件系统解析(一)
    B、硬盘物理结构和FAT文件系统解析(二)
好多图片打不开,楼主有办法吗?

wodetianmyday 发表于 2009-11-23 16:06:10

文件系统

plantniu 发表于 2009-11-23 16:18:11

mark

wodetianmyday 发表于 2009-11-23 16:21:41

在文件读取中
   
    dwSectorNumber = pFATBPB->BPB_ResvdSecCnt +
                ((dwCluster * 4) / (pFATBPB->BPB_BytePerSec));
    wByteOffset = (dwCluster * 4) % (pFATBPB->BPB_BytePerSec);


怎么理解?

avrwoo 发表于 2009-11-23 16:22:40

谢谢。MARK

ideality0214 发表于 2009-11-25 00:18:10

mark

flyan.oo 发表于 2009-11-27 09:48:47

mark 这几天在研究U盘FAT系统的文件创建与读写,怎样查询已用空间和分配新的存储空间貌似比较麻烦,不知道有什么好的方法

XUEPENGBIN 发表于 2009-12-1 16:45:33

着几天正在用收藏了~

siway 发表于 2009-12-9 01:07:00

傻孩子工作没有?
有这么多时间整理资料

xihacow 发表于 2009-12-9 08:56:19

学习学习文件系统

hy317 发表于 2009-12-9 08:59:52

mark

zzwuyu 发表于 2010-1-22 09:27:48

谢谢,最近正准备做这方面的工作

avrmk 发表于 2010-1-22 09:47:36

mark!

aiyu 发表于 2010-1-26 15:02:33

mark

gxy508 发表于 2010-1-26 16:57:42

mark

wuzhujian 发表于 2010-1-26 17:45:57

顶一下。

hbtswy 发表于 2010-1-26 22:00:33

mark

idly 发表于 2010-1-29 10:00:05

好帖

swan1225 发表于 2010-2-3 16:05:58

谢谢分享

dragonx 发表于 2010-2-4 23:13:21

做个记号

rodger 发表于 2010-2-5 02:27:13

顶一下。

kinoko 发表于 2010-2-9 14:44:00

继续学习…标记

sddp001 发表于 2010-2-9 20:06:16

mark

whh217 发表于 2010-2-9 20:33:10

记号!!!

bitant 发表于 2010-2-26 12:26:18

Mark 一下,有空来学习。

ep1c3 发表于 2010-3-4 16:33:44

有时间在看

pinocchio 发表于 2010-3-4 17:43:30

mark

quzegang 发表于 2010-3-4 20:18:19

MARK

lyping1987 发表于 2010-3-4 21:40:07

mark!

liitom 发表于 2010-3-16 16:32:50

好贴

zhao_123456 发表于 2010-3-16 19:07:00

mark

hxx_123 发表于 2010-3-23 20:45:54

呵呵,我只看到mark等,有多少人实际分析!都一看都懂吗?一点疑问也没有,奇怪!呵呵

wzhansen 发表于 2010-3-23 21:32:48

mark

lib393654223 发表于 2010-3-29 10:50:02

mark

cgbabc 发表于 2010-3-29 11:23:21

今天才发现这个好贴,晚了,晚了

chahu1227 发表于 2010-4-22 17:36:07

mark

gdourf 发表于 2010-4-22 17:45:48

顶了
页: [1] 2 3
查看完整版本: [开源][交流]如何读写FAT32文件系统(9-24-2008 Updated)