一、FATFS文件系统基础知识

1.简介

文件系统可以从官网进行下载

官网地址:http://elm-chan.org/fsw/ff/00index_e.html

FATFS是一个完全免费开源的FAT 文件系统模块,FatFs模块是按照ANSI C(C89)编写的,并且与磁盘I / O层完全分开,它支持FATl2、FATl6 和FAT32,支持多个存储媒介,有独立的缓冲区,可以对多个文件进行读/写,并特别对8 位单片机和16 位单片机做了优化,。因此,它独立于平台。它可以并入资源有限的小型微控制器中,例如8051,PIC,AVR,ARM,Z80,RX等,具有良好的硬件平台独立性。

2.特征

  • DOS / Windows兼容的FAT / exFAT文件系统。
  • 平台无关。容易移植。
  • 程序代码和工作区的占用空间非常小。
  • 支持以下各种配置选项:
  • ANSI / OEM或Unicode中的长文件名。
  • exFAT文件系统,64位LBA和GPT可存储大量数据。
  • RTOS的线程安全。
  • 多个卷(物理驱动器和分区)。
  • 可变扇区大小。
  • 多个代码页,包括DBCS。
  • 只读,可选API,I / O缓冲区等

二、文件接口

1.f_open

函数作用:

f_open`函数打开一个文件,并创建一个文件对象。文件对象用于随后对文件的读/写操作以标识文件。访问文件的会话之后,应使用f_close函数关闭打开的文件。如果对文件进行了任何更改并且在关闭电源之前未关闭文件,则介质移除或重新安装或文件可能会折叠。

函数体:

FRESULT f_open(
  FIL * fp,            / * 指向文件对象结构的指针* / 
  const TCHAR * path,/ * 文件名* / 
  BYTE mode          / * 模式标志* /
);

参数含义:

fp:指向空白文件对象结构的指针。

路径:指向以空值结尾的字符串的指针,该字符串指定要打开或创建的文件名。如:“0:message.txt"

模式:

标志

含义

FA_READ

指定对对象的读取访问权限。可以从文件中读取数据。

FA_WRITE

指定对对象的写访问。数据可以写入文件。与FA_READ结合使用进行读写访问。

FA_OPEN_EXISTING

打开文件。如果文件不存在,该功能将失败。(默认)

FA_CREATE_NEW

创建一个新文件。如果该文件存在,则函数失败并显示FR_EXIST

FA_CREATE_ALWAYS

创建一个新文件。如果文件已存在,它将被截断并覆盖。

FA_OPEN_ALWAYS

打开文件(如果存在)。如果没有,将创建一个新文件。

FA_OPEN_APPEND

FA_OPEN_ALWAYS相同,不同之处在于将读/写指针设置为文件的结尾。

举例:

2.f_close

函数作用:

f_close函数关闭一个打开的文件对象。如果文件已更改,则文件的缓存信息将写回到该卷。函数成功后,文件对象不再有效,可以将其丢弃。

函数体

FRESULT f_close (
  FIL* fp     /* 指向文件对象的指针 */
);

3.f_read

函数作用:

该函数以读/写指针指向的文件偏移量开始从文件中读取数据。读/写指针随着读取的字节数而增加。函数成功后,应检查* br以检测文件结尾。如果* br < btr,则意味着在读操作期间读/写指针到达文件的末尾。

FRESULT f_read(
  FIL * fp,      / * [IN]文件对象* / 
  void * buff,   / * [OUT]存储读取数据的缓冲区* / 
  UINT btr,     / * [IN]要读取的字节数* / 
  UINT * br      / * [OUT]读取的字节数* / 
);

4.f_write

函数作用 :

函数开始在读/写指针指向的文件偏移量处向文件写入数据。读/写指针随着写入的字节数而增加。函数成功后,应检查bw以检测磁盘已满。如果bw<btw,则表示写入操作期间卷已满。当卷已满或接近满时,此功能可能需要一段时间。

函数体:

FRESULT f_write(
  FIL * fp,           / * [IN]指向文件对象结构的指针* / 
  const void * buff,/ * [IN]指向要写入的数据的指针* / 
  UINT btw,          / * [IN]要写入的字节数* / 
  UINT * bw           / * [OUT]指向变量的指针,以返回写入的字节数* /
);

5.f_gets

函数作用:

读取操作将继续进行,直到存储了一个'\ n',到达文件末尾或缓冲区中的len-1个字符为止。读取的字符串以'\ 0'终止。当没有字符要读取或在读取操作期间发生任何错误时,它将返回空指针。可以使用f_eof和f_error函数检查EOF和错误的状态。

函数体:

TCHAR * f_gets(
  TCHAR * buff,/ * [OUT]读取缓冲区* / 
  int len,      / * [IN]读取缓冲区的大小* / 
  FIL * fp       / * [IN]文件对象* /
);

6.f_puts

函数作用:

成功写入字符串后,它将返回写入文件的字符编码单元数。当功能由于磁盘已满或任何错误而失败时,将返回EOF(-1)。

 函数体:

int f_puts(
  const TCHAR * str,/ * [IN]字符串* / 
  FIL * fp            / * [IN]文件对象* /
);

读/写一个字符和读/写一个字符串大致相同,将要读/写入的变量定义成TCHAR即可。 

7.f_eof

函数作用:

f_eof函数测试文件的文件结尾,如果读/写指针已到达文件的结束则返回一个非零值; 否则返回零。

函数体:

int f_eof(
  FIL * fp    / * [IN]文件对象* /
);

8.f_error

函数作用:

检测文件系统是否发生硬件错误,若未发生异常返回一个非零值,发生异常则返回0。

函数体:

int f_error (
  FIL* fp   /* [IN] File object */
);

 

整体应用:

/* Read a text file and display it */

FATFS FatFs;   /* Work area (filesystem object) for logical drive */

int main (void)
{
    FIL fil;        /* File object */
    char line[100]; /* Line buffer */
    FRESULT fr;     /* FatFs return code */


    /* Gives a work area to the default drive */
    f_mount(&FatFs, "", 0);

    /* Open a text file */
    fr = f_open(&fil, "message.txt", FA_READ);    
if (fr) return (int)fr;

    /* Read every line and display it */
    while (f_gets(line, sizeof line, &fil)) {
        printf(line);
    }

    /* Close the file */
    f_close(&fil);

    return 0;
}
/* Copy a file "file.bin" on the drive 1 to drive 0 */

int main (void)
{
    FATFS fs0, fs1;      /* Work area (filesystem object) for logical drives */
    FIL fsrc, fdst;      /* File objects */
    BYTE buffer[4096];   /* File copy buffer */
    FRESULT fr;          /* FatFs function common result code */
    UINT br, bw;         /* File read/write count */


    /* Gives work area to each logical drive */
    f_mount(&fs0, "0:", 0);
    f_mount(&fs1, "1:", 0);

    /* Open source file on the drive 1 */
    fr = f_open(&fsrc, "1:file.bin", FA_READ);
    if (fr) return (int)fr;

    /* Create destination file on the drive 0 */
    fr = f_open(&fdst, "0:file.bin", FA_WRITE | FA_CREATE_ALWAYS);
    if (fr) return (int)fr;

    /* Copy source to destination */
    for (;;) {
        f_read(&fsrc, buffer, sizeof buffer, &br);  /* Read a chunk of data from the source file */
        if (br == 0) break; /* error or eof */
        f_write(&fdst, buffer, br, &bw);            /* Write it to the destination file */
        if (bw < br) break; /* error or disk full */
    }

    /* Close open files */
    f_close(&fsrc);
    f_close(&fdst);

    /* Unregister work area prior to discard it */
    f_mount(0, "0:", 0);
    f_mount(0, "1:", 0);

    return (int)fr;
}

三、目录接口 

1.f_opendir

函数作用:

打开已存在的目录,并且为随后使用到的f_readdir函数创建一个目录对象。

函数体:

FRESULT f_opendir (
  DIR* dp,           /* [OUT] Pointer to the directory object structure */
  const TCHAR* path  /* [IN] Directory name */
);

2.f_clodedir

函数作用:

关闭一个打开的目录,当函数作用成功后,目录对象不再有效,可以被丢弃。

函数体:

FRESULT f_closedir (
  DIR* dp     /* [IN] Pointer to the directory object */
);

3.f_findfirst

函数作用:

在可以打开路径指定的目录后,它开始搜索目录中具有模式指定的匹配模式的项目。如果找到第一个项,则有关该项的信息将存储在文件信息结构fno 中。

函数体:

FRESULT f_findfirst (
  DIR* dp,              /* [OUT] Poninter to the directory object */
  FILINFO* fno,         /* [OUT] Pointer to the file information structure */
  const TCHAR* path,    /* [IN] Pointer to the directory name to be opened */
  const TCHAR* pattern  /* [IN] Pointer to the matching pattern string */
);

参数:

Dp:

指向空白目录对象的指针。

fno:

指向文件信息结构的指针,以存储有关找到的项的信息。

path:

指向指定要打开的目录名称的空终止字符串的指针。

mode:

指向 nul 终止字符串的指针,该字符串指定要搜索的名称匹配模式。它由后续函数f_findnext引用,因此字符串在连续函数调用时必须有效。

4.f_findnext

函数作用:

它继续搜索从上一个调用到f_findfirst或f_findnext函数。如果找到,有关该对象的信息将存储在文件信息结构中。如果没有要读取的项,则空字符串将返回到fno->fname= 中。

函数体:

FRESULT f_findnext (
  DIR* dp,              /* [IN] Poninter to the directory object */
  FILINFO* fno          /* [OUT] Pointer to the file information structure */
);

 

应用示例:

/* Search a directory for objects and display it */

void find_image_file (void)
{
    FRESULT fr;     /* Return value */
    DIR dj;         /* Directory object */
    FILINFO fno;    /* File information */

    fr = f_findfirst(&dj, &fno, "", "dsc*.jpg");  /* Start to search for photo files */

    while (fr == FR_OK && fno.fname[0]) {         /* Repeat while an item is found */
        printf("%s\n", fno.fname);                /* Print the object name */
        fr = f_findnext(&dj, &fno);               /* Search for next item */
    }

    f_closedir(&dj);
}

对于其中的f_findfirst函数调用,可以使用通配符匹配,包含通配符(? 和 *)。例如,与任何字符匹配,* 匹配长度为零或更长的任何字符串,并且???* 匹配长度为 3 个字符或更长的任何字符串,例中dsc*.jpg就是指dsc开头,后面任意长度内容最后以.jpg结尾的字符串。

四、卷管理和系统配置接口

1.f_mount

函数作用:

FatFs 需要每个逻辑驱动器(FAT 卷) 的工作区 ( 文件系统对象 )。在执行任何文件/目录操作之前,需要向逻辑驱动器的f_mount注册文件系统对象。此过程后,文件/目录 API 函数即可开始工作。某些卷管理函数f_mkfs,f_fdisk,f_setcp和文件,不需要文件系统对象。

f_mount将文件系统对象注册/取消注册到 FatF 模块,如下所示:

  • 确定由路径指定的逻辑驱动器。
  • 清除和取消注册卷的重新注册工作区(如果存在)。
  • 如果fs不是 NULL,则清除新工作区并注册到卷。
  • 如果指定了强制装载,则对卷执行卷装载过程。

如果逻辑驱动器上有任何打开的文件或目录对象,则该对象将因此函数而失效。

如果未指定强制安装(选择= 0),则无论物理驱动器状态如何,此功能始终成功。它只清除(去初始化)给定工作区,并将其地址注册到内部表,并且此函数中的物理驱动器没有活动。如果未初始化文件系统对象,则将在后续文件/直接函数上尝试卷装载过程。(延迟安装)卷装载进程,初始化相应的物理驱动器,查找其中 FAT 卷,然后初始化工作区,在后续文件/目录函数中执行,当以下任一条件为真时。

  • 文件系统对象尚未初始化。它由函数f_mount初始化。
  • 物理驱动器未初始化。它通过系统重置或介质移除而取消初始化。

如果强制安装(opt = 1) FR_NOT_READY失败,则表示文件系统对象已成功注册,但卷当前尚未准备好工作。将在后续文件/直接函数上尝试卷装载过程。

如果磁盘 I/O 层的实现缺少异步介质更改检测,则应用程序需要在每次介质更改后执行 f_mount函数以强制清除文件系统对象。

要取消注册工作区,指定一个 NULL 到fs,然后可以丢弃工作区。

简言之就是起到一个挂载作用。

函数体:

FRESULT f_mount (
  FATFS*       fs,    /* [IN] Filesystem object */
  const TCHAR* path,  /* [IN] Logical drive number */
  BYTE         opt    /* [IN] Initialization option */
);

参数:

fs:

指向要注册和清除的文件系统对象的指针。空指针取消注册文件系统对象。

path:

指向指定逻辑驱动器的空终止字符串的指针。不带驱动器号的字符串表示默认驱动器。

opt:

安装选项。0:现在不要装载(要装载在第一次访问卷上),1:强制装载卷以检查卷是否已准备好工作。

 

实例: 

int main (void)
{
    FATFS *fs;     /* Ponter to the filesystem object */


    fs = malloc(sizeof (FATFS));           /* Get work area for the volume */
    f_mount(fs, "", 0);                    /* Mount the default drive */

    f_open(...                             /* Here any file API can be used */

    ...

    f_mount(fs, "", 0);                    /* Re-mount the default drive to reinitialize the filesystem */

    ...

    f_mount(0, "", 0);                     /* Unmount the default drive */
    free(fs);                              /* Here the work area can be discarded */

    ...
}

2.f_mkfs

函数作用:该f_mkfs在逻辑驱动器上创建 FAT/exFAT 卷。

函数体:

FRESULT f_mkfs (
  const TCHAR*  path,  /* [IN] Logical drive number */
  const MKFS_PARM* opt,/* [IN] Format options */
  void*  work,         /* [-]  Working buffer */
  UINT  len            /* [IN] Size of working buffer */
);

参数:

  • path:

指向空终止字符串的指针指定要格式化的逻辑驱动器。如果它没有驱动器号,则意味着指定默认驱动器。逻辑驱动器可能已装载,也可能未为格式进程安装。

  • opt:

指定保存格式选项的结构。如果给定一个空指针,它将为函数提供默认值中的所有选项。格式选项结构有五个成员,描述如下:

  • BYTE fmt:

指定 FAT 类型标志、FM_FAT、FM_FAT32、FM_EXFAT和位或这三个标记的组合FM_ANY。 FM_EXFAT启用 exFAT 时,将忽略此错误。这些标志指定要在卷上创建的 FAT 类型。如果指定了两种或两种类型,则将选择其中一种类型,这取决于卷大小和au_size。标志FM_SFD指定以 SFD 格式在驱动器上创建卷。默认值为FM_ANY。

  • DWORD au_size:

指定以字节单位表示分配单位(cluter)的大小。有效值是扇区大小之间的 2 和 128 * 扇区大小的功率,包括 FAT/FAT32 卷和高达 16 MB 的 exFAT 卷。如果给出零(默认值)或任何无效值,则默认分配单位大小取决于使用的卷大小。

  • UINT n_align:

指定卷数据区域(文件分配池,通常擦除闪存介质的块边界)在扇区单位中的对齐方式。此成员的有效值介于 1 和 32768 之间,包括 2。如果给出零(默认值)或任何无效值,则函数会从具有"一个函数"的较低层disk_ioctl大小。

  • BYTE n_fat:

指定 FAT/FAT32 卷上的 FAT 副本数。此成员的有效值为 1 或 2。默认值 (0) 和任何 invaid 值给出 1。如果 FAT 类型为 exFAT,则此成员不起作用。

  • UINT n_root:

指定 FAT 卷上的根目录条目数。此成员的有效值高达 32768,与扇区大小 / 32 对齐。默认值 (0) 和任何 invaid 值给出 512。如果 FAT 类型为 FAT32 或 exFAT,则此成员不起作用。

  • work:

指向用于格式化过程的工作缓冲区的指针。当一个空指针被用FF_USE_LFN==3进行赋值时,函数将在此函数中为工作缓冲区获取内存块。

  • len:

工作缓冲区的大小(以字节单位表示)。它至少需要FF_MAX_SS一点。大量工作缓冲区减少了驱动器的写入事务数,并且格式过程将快速完成。

实例:

/* Format default drive and create a file */
int main (void)
{
    FATFS fs;           /* Filesystem object */
    FIL fil;            /* File object */
    FRESULT res;        /* API result code */
    UINT bw;            /* Bytes written */
    BYTE work[FF_MAX_SS]; /* Work area (larger is better for processing time) */


    /* Format the default drive with default parameters */
    res = f_mkfs("", 0, work, sizeof work);
    if (res) ...

    /* Gives a work area to the default drive */
    f_mount(&fs, "", 0);

    /* Create a file as new */
    res = f_open(&fil, "hello.txt", FA_CREATE_NEW | FA_WRITE);
    if (res) ...

    /* Write a message */
    f_write(&fil, "Hello, World!\r\n", 15, &bw);
    if (bw != 15) ...

    /* Close the file */
    f_close(&fil);

    /* Unregister work area */
    f_mount(0, "", 0);

    ...

3.f_getfree

函数作用:

获取卷上可用的集群数。

函数体:

FRESULT f_getfree (
  const TCHAR* path,  /* [IN] Logical drive number */
  DWORD* nclst,       /* [OUT] Number of free clusters */
  FATFS** fatfs       /* [OUT] Corresponding filesystem object */
);

参数:

path:

指向指定逻辑驱动器的空终止字符串的指针。空字符串表示默认驱动器。

nclst:

指向DWORD 类型的指针以存储可用群集的数量。

fatfs:

指向指针,用于存储指向相应文件系统对象的指针。

实例:

FATFS *fs;
    DWORD fre_clust, fre_sect, tot_sect;


    /* Get volume information and free clusters of drive 1 */
    res = f_getfree("1:", &fre_clust, &fs);
    if (res) die(res);

    /* Get total sectors and free sectors */
    tot_sect = (fs->n_fatent - 2) * fs->csize;
    fre_sect = fre_clust * fs->csize;

    /* Print the free space (assuming 512 bytes/sector) */
    printf("%10lu KiB total drive space.\n%10lu KiB available.\n", tot_sect / 2, fre_sect / 2);