FatFs文件访问接口中文版

发布于:2022-11-28 ⋅ 阅读:(473) ⋅ 点赞:(0)

▼我是阿荣,关注我,在技术路上一起精进!▼

引言

FatFs是通用的FAT/exFAT文件系统模块,适用于小型嵌入式系统的。FatFs支持FAT12、FAT16、FAT32等格式。本文将参考FatFs官网资料,讲解应用接口的使用方法。atFs是通用的FAT/exFAT文件系统模块,适用于小型嵌入式系统的。FatFs支持FAT12、FAT16、FAT32等格式。本文将参考FatFs官网资料,讲解应用接口的使用方法。

应用接口

FatFs为应用程序提供了各种文件系统功能。这些功能将完成文件的创建,打开,读出,写入,关闭等功能。

文件访问

f_open - 打开/创建文件

函数原型

FRESULT f_open (
  FIL* fp,           /* [OUT] Pointer to the file object structure */
  const TCHAR* path, /* [IN] File name */
  BYTE mode          /* [IN] Mode flags */
);

形参
fp
文件指针。
path
指向以NULL结尾的字符串的指针,该字符串指定要打开或创建的文件名。
mode
模式标志,用于指定文件的访问类型和打开方法。它由以下标志的组合指定。

标志 描述
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相同,只是读/写指针设置在文件末尾。

POSIX中的fopen函数的模式标志与FatFs模式标志的对应关系如下所示:

POSIX FatFs
“r” FA_READ
“r+” FA_READ,FA_WRITE
“w” FA_CREATE_ALWAYS,FA_WRITE
“w+” FA_CREATE_ALWAYS,FA_WRITE,FA_READ
“a” FA_OPEN_APPEND,FA_WRITE
“a+” FA_OPEN_APPEND,FA_WRITE,FA_READ
“wx” FA_CREATE_NEW,FA_WRITE
“w+x” FA_CREATE_NEW,FA_WRITE,FA_READ

注:由于编辑器原因,FatFs列内容中逗号要替换成或符号。
返回值
FR_OK, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, FR_NO_PATH, FR_INVALID_NAME, FR_DENIED, FR_EXIST, FR_INVALID_OBJECT, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_LOCKED, FR_NOT_ENOUGH_CORE, FR_TOO_MANY_OPEN_FILES
描述
f_open函数打开一个文件并创建一个文件对象。文件对象用于对文件进行后续读/写操作,以标识文件。在文件访问会话结束后,应使用f_close函数关闭打开的文件。如果在断电前对文件进行了任何更改,但未做关闭操作,则有可能会出现介质被移除或重新装载,或者文件被折叠的现象。
如果需要打开重复文件,请仔细阅读此处。但是,始终禁止使用任何写入模式标志重复打开文件。
示例

/* 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 */


    /* Give work areas 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 (;;) {
        fr = f_read(&fsrc, buffer, sizeof buffer, &br); /* Read a chunk of data from the source file */
        if (br == 0) break; /* error or eof */
        fr = 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_unmount("0:");
    f_unmount("1:");

    return (int)fr;
}

f_close - 关闭打开的文件

函数原型

FRESULT f_close (
  FIL* fp     /* [IN] Pointer to the file object */
);

形参
fp
文件指针。
返回值
FR_OK, FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_TIMEOUT
描述
f_close函数关闭打开的文件对象。如果文件已更改,则文件的缓存信息将写回卷。函数成功后,文件对象不再有效,可以将其丢弃。请注意,如果文件对象处于只读模式且未启用FF_FS_LOCK,则也可以在不执行此过程的情况下丢弃文件对象。但是,出于将来的兼容性考虑,不建议这么做。
示例
参考f_open示例。

f_read - 从文件中读取数据

函数原型

FRESULT f_read (
  FIL* fp,     /* [IN] File object */
  void* buff,  /* [OUT] Buffer to store read data */
  UINT btr,    /* [IN] Number of bytes to read */
  UINT* br     /* [OUT] Number of bytes read */
);

形参
fp
文件指针。。
buff
指向存储读取数据的缓冲区的指针。
btr
UINT类型范围内要读取的字节数。
br
指向接收读取字节数的UINT变量的指针。无论函数返回值如何,此值在函数调用后始终有效。如果返回值等于btr,则函数返回值应为FR_OK。
返回值
FR_OK, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, FR_INVALID_OBJECT, FR_TIMEOUT
描述
函数在读/写指针指向的文件偏移量处开始从文件读取数据。读/写指针随着读取的字节数而向前移动。在函数调用成功后,应根据br来检测是否到达文件的末尾。在br<btr的情况下,表示读/写指针在读操作期间到达文件的末尾。
示例
参考f_open示例。

f_write - 将数据写入文件

函数原型

FRESULT f_write (
  FIL* fp,          /* [IN] Pointer to the file object structure */
  const void* buff, /* [IN] Pointer to the data to be written */
  UINT btw,         /* [IN] Number of bytes to write */
  UINT* bw          /* [OUT] Pointer to the variable to return number of bytes written */
);

形参
fp
文件指针。
buff
指向要写入的数据的指针。
btw
指定要在UINT类型范围内写入的字节数。
bw
指向接收写入字节数的UINT变量的指针。无论函数返回值如何,此值在函数调用后始终有效。如果返回值等于btw,则函数返回值应为FR_OK。
返回值
FR_OK, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, FR_INVALID_OBJECT, FR_TIMEOUT
描述
函数开始在读/写指针指向的文件偏移量处向文件写入数据。读/写指针随着写入的字节数的增加而向前移动。在函数调用成功后,应检查bw以检测卷是否已满。如果bw<btw,则表示在写入操作期间卷已满。当卷已满或接近满时,该功能可能需要一段时间。
示例
参考f_open示例。

f_lseek - 移动读/写指针,扩展大小

函数原型

FRESULT f_lseek (
  FIL*    fp,  /* [IN] File object */
  FSIZE_t ofs  /* [IN] Offset of file read/write pointer to be set */
);
FRESULT f_rewind (
  FIL*    fp   /* [IN] File object */
);

形参
fp
指向打开文件对象的指针。
ofs
从文件顶部到设置读/写指针的字节偏移量。数据类型FSIZE_t是DWORD(32位)或QWORD(64位)的别名,具体取决于配置选项FF_FS_EXFAT。
返回值
FR_OK, FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_TIMEOUT
描述
打开的文件对象指针中的文件读/写指针指向下一次读/写操作时要读/写的数据字节。它随着读取/写入的字节数的增加而增加。f_lseek函数可移动文件读/写指针,而无需对文件执行任何读/写操作。f_rewind函数作为一个宏进行使用。

#define f_rewind(fp) f_lseek((fp), 0)

如果在写入模式下指定了超出文件大小的偏移量,则文件大小将扩展到指定的偏移量。扩展区域中的文件数据未定义,因为在此过程中没有数据写入该扩展区域。这适用于为文件快速预分配数据区域,以进行快速写入操作。当需要为文件分配连续数据区域时,请改用f_expand函数。在f_lseek函数调用成功后,应检查当前读/写指针,以确保读/写指针已正确移动。如果读/写指针未指向预期的偏移量,则发生以下任一情况。

  • 文件结束。在只读模式下,在文件末尾剪裁了指定的ofs。
  • 磁盘已满。卷上没有扩展文件的可用空间。快速寻找功能通过使用内存CLMT(群集链接映射表)实现快速向后/长寻找操作,而无需FAT访问。它也适用于f_write和f_read函数,但是,当文件处于快速寻找模式时,f_write和f_lseek函数无法扩展文件大小。
    当FF_USE_FASTSEEK=1时,快速寻找模式可用。在使用快速寻找模式之前,必须在DWORD数组中创建CLMT。要创建CLMT,请将DWORD数组的地址赋值给打开的文件对象中的成员cltbl,将以项为单位的数组大小赋值给cltbl[0],然后通过ofs=create_LINKMAP来调用f_lseek函数。在函数调用成功后,在文件的后续f_wirte、f_read、f_lseek函数中不会发生FAT访问。已使用或需要的项数将返回到cltbl[0]中。所需项数为(文件片段数+1)*2。例如,数组中的12项将用于分为5个部分的文件。如果函数失败,FR_NOT_ENOUGH_CORE不足,则给定数组的大小不足以容纳文件。
    示例
/* Using fast seek mode */

    DWORD clmt[SZ_TBL];                    /* Cluster link map table buffer */

    res = f_open(fp, fname, FA_READ | FA_WRITE);   /* Open a file */

    res = f_lseek(fp, ofs1);               /* This is normal seek (cltbl is nulled on file open) */

    fp->cltbl = clmt;                      /* Enable fast seek mode (cltbl != NULL) */
    clmt[0] = SZ_TBL;                      /* Set table size */
    res = f_lseek(fp, CREATE_LINKMAP);     /* Create CLMT */
    ...

    res = f_lseek(fp, ofs2);               /* This is fast seek */

f_truncate - 截断文件大小

函数原型

FRESULT f_truncate (
  FIL* fp     /* [IN] File object */
);

形参
fp
文件指针。
返回值
FR_OK, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, FR_INVALID_OBJECT, FR_TIMEOUT
描述
f_truncate函数截断文件到当前的文件读/写指针。如果文件读/写指针已经指向文件的末尾,则此函数无效。

f_sync - 刷新缓存数据

函数原型

FRESULT f_sync (
  FIL* fp     /* [IN] File object */
);

形参
fp
文件指针。
返回值
FR_OK, FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_TIMEOUT
描述
f_sync函数执行与f_close函数相同的过程,但文件保持打开状态,可以继续对文件执行读/写/查找操作。这适用于在写入模式下长时间打开文件的应用程序,如数据记录器。在一定的时间间隔内执行f_sync功能可以最大限度地降低因突然断电、错误的介质移除或无法恢复的磁盘错误而导致数据丢失的风险。有关更多信息,请参阅应用说明。

Case 1. Normal write sequence

                                Time -->                                     ↓Normal shutdown
OwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwC <Power off>


Case 2. Without using f_sync()

                                Time -->                             ↓System crush
Owwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
 |<--------------- All data written will be lost ------------------>|


Case 3. Using f_sync()
                                Time -->                             ↓System crush
OwwwwwwwwSwwwwwwwwSwwwwwwwwSwwwwwwwwSwwwwwwwwSwwwwwwwwSwwwwwwwwSwwwww
                            Data after last f_sync will be lost |<->| 
O - f_open()
C - f_close()
w - f_write()
S - f_sync()

然而,在调用f_close函数之前,立刻调用f_sync函数是没有任何意义的,因为它在其中已执行f_sync函数的功能。换句话说,这些函数之间的区别在于文件对象是否无效。

f_forward - 将数据转发到流

函数原型

FRESULT f_forward (
  FIL* fp,                        /* [IN] File object */
  UINT (*func)(const BYTE*,UINT), /* [IN] Data streaming function */
  UINT btf,                       /* [IN] Number of bytes to forward */
  UINT* bf                        /* [OUT] Number of bytes forwarded */
);

形参
fp
文件指针。
func
指向用户定义的数据流函数的指针。有关详细信息,请参阅示例代码。
btf
UINT范围内要转发的字节数。
bf
指向UINT变量的指针,以返回转发的字节数。
返回值
FR_OK, FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_DENIED, FR_TIMEOUT
描述
f_forward函数从文件中读取数据,并将其转发到不带数据缓冲区的输出流。这适用于小型内存系统,因为它不需要应用程序的任何数据缓冲区。文件指针增加了转发的字节数。如果*bf小于btf且没有错误,则表示由于文件结束或数据传输期间流繁忙,无法传输请求的字节。
示例

/*------------------------------------------------------------------------*/
/* Sample code of data transfer function to be called back from f_forward */
/*------------------------------------------------------------------------*/

UINT out_stream (   /* Returns number of bytes sent or stream status */
    const BYTE *p,  /* Pointer to the data block to be sent */
    UINT btf        /* >0: Transfer call (Number of bytes to be sent). 0: Sense call */
)
{
    UINT cnt = 0;


    if (btf == 0) {     /* Sense call */
        /* Return stream status (0: Busy, 1: Ready) */
        /* When once it returned ready to sense call, it must accept a byte at least */
        /* at subsequent transfer call, or f_forward will fail with FR_INT_ERR. */
        if (FIFO_READY) cnt = 1;
    }
    else {              /* Transfer call */
        do {    /* Repeat while there is any data to be sent and the stream is ready */
            FIFO_PORT = *p++;
            cnt++;
        } while (cnt < btf && FIFO_READY);
    }

    return cnt;
}


/*------------------------------------------------------------------------*/
/* Sample code using f_forward function                                   */
/*------------------------------------------------------------------------*/

FRESULT play_file (
    char *fn        /* Pointer to the audio file name to be played */
)
{
    FRESULT rc;
    FIL fil;
    UINT dmy;

    /* Open the audio file in read only mode */
    rc = f_open(&fil, fn, FA_READ);
    if (rc) return rc;

    /* Repeat until the file pointer reaches end of the file */
    while (rc == FR_OK && !f_eof(&fil)) {

        /* some processes... */

        /* Fill output stream periodicaly or on-demand */
        rc = f_forward(&fil, out_stream, 1000, &dmy);
    }

    /* Close the file and return */
    f_close(&fil);
    return rc;
}

f_expand - 将连续块分配给文件

函数原型

FRESULT f_expand (
  FIL*    fp,  /* [IN] File object */
  FSIZE_t fsz, /* [IN] File size expanded to */
  BYTE    opt  /* [IN] Allocation mode */
);

形参
fp
文件指针。
fsz
为文件准备或分配的字节数。数据类型FSIZE_t是DWORD(32位)或QWORD(64位)的别名,具体取决于配置选项FF_FS_EXFAT。
opt
分配模式。准备分配(0)或立即分配(1)。
返回值
FR_OK, FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_DENIED, FR_TIMEOUT
描述
f_expand函数为文件准备或分配一个连续的数据区域。当opt为1时,数据区域将分配给该文件在此函数中。与通过f_lseek函数扩展文件大小不同,在使用此函数之前必须截断文件,并且在函数调用后,文件的读/写指针保持在偏移量0处。使用此函数分配的文件内容未定义,因为在此过程中没有数据写入文件。由于以下原因,功能可能会失败,并返回 FR_DENIED。

  • 找不到可用的连续空间。
  • 文件的大小不是零。
  • 该文件已以只读模式打开。
  • 不允许的文件大小。(>=4 GB在FAT的磁盘上)

当opt为0时,函数将查找一个连续的数据区域,并将其设置为下一次分配的建议点。随后的集群分配从该函数找到的相邻区域的顶部开始。因此,除非对卷执行任何其他更改,否则在文件大小达到此大小之前,保证文件分配是连续的且没有分配延迟。

连续文件对于时间关键型读/写操作具有优势。它消除了文件系统和存储设备中由于随机访问碎片文件而产生的一些开销。

此外,可以通过低级磁盘功能轻松地直接访问连续文件。但是,考虑到可移植性和未来的兼容性,不建议这样做。如果未确认文件是否连续,请使用此函数检查文件是否连续。
示例

    /* Creating a contiguous file */

    /* Create a new file */
    res = f_open(fp = malloc(sizeof (FIL)), "file.dat", FA_WRITE|FA_CREATE_ALWAYS);
    if (res) { /* Check if the file has been opened */
        free(fp);
        die("Failed to open the file.");
    }

    /* Alloacte a 100 MiB of contiguous area to the file */
    res = f_expand(fp, 104857600, 1);
    if (res) { /* Check if the file has been expanded */
        f_close(fp);
        free(fp);
        die("Failed to allocate contiguous area.");
    }

    /* Now you have a contiguous file accessible with fp */

    /* Accessing the contiguous file via low-level disk functions */

    /* Get physical location of the file data */
    drv = fp->obj.fs->pdrv;
    lba = fp->obj.fs->database + fp->obj.fs->csize * (fp->obj.sclust - 2);

    /* Write 2048 sectors from top of the file at a time */
    res = disk_write(drv, buffer, lba, 2048);

f_gets - 读字符串

函数原型

TCHAR* f_gets (
  TCHAR* buff, /* [OUT] Read buffer */
  int len,     /* [IN] Size of the read buffer */
  FIL* fp      /* [IN] File object */
);

形参
buff
指向存储读取字符串的读取缓冲区的指针。
len
读取缓冲区的大小(以unit为单位)。
fp
文件指针。
返回值
当函数成功时,将返回buff。
描述
读取操作将继续,直到遇到“\n”、到达文件末尾或缓冲区中已填充了len-1个字符。读取字符串以“\0”结尾。当没有要读取的字符或读取操作期间发生任何错误时,它将返回空指针。可以使用f_eof和f_error函数检查EOF和错误的状态。
当FatFs配置为Unicode API(FF_LFN_Unicode>=1)时,srting函数、f_putc、f_puts、f_printf和f_gets上的数据类型也会切换为Unicode。通过此函数读取的文件上的字符编码假定为FF_STRF_ENCODE。如果文件上的字符编码不同于API上的字符编码,则在此函数中进行转换。在这种情况下,编码错误的输入字符将丢失。

f_putc - 写一个字符

函数原型

int f_putc (
  TCHAR chr,  /* [IN] A character to write */
  FIL* fp     /* [IN] File object */
);

形参
chr
要写的字符。
fp
文件指针。
返回值
成功写入字符后,它返回写入文件的字符编码单元数。当函数由于磁盘已满或任何错误而失败时,将返回负值。
描述
当FatFs配置为Unicode API(FF_LFN_Unicode>=1)时,字符串函数、f_putc、f_puts、f_printf和f_gets函数上的字符编码也会切换为Unicode。通过这些函数读取/写入的文件上的字符编码由FF_STRF_ENCODE选择。无法使用此函数写入多重编码单元中的Unicode字符,例如代理对和多字节序列。

f_puts - 写一个字符串

函数原型

int f_puts (
  const TCHAR* str, /* [IN] String */
  FIL* fp           /* [IN] File object */
);

形参
str
指向要写入的以null结尾的字符串的指针。不会写入终止符字符。
fp
文件指针。
返回值
成功写入字符串后,它返回写入文件的字符编码单元数。当函数由于磁盘已满或任何错误而失败时,将返回负值。
描述
当FatFs配置为Unicode API(FF_LFN_Unicode>=1)时,字符串函数、f_putc、f_puts、f_printf和f_gets函数上的字符编码也会切换为Unicode。在多重编码单元中输入的Unicode字符,如代理项对和多字节序列,不应分为两个函数调用,否则字符将丢失。要通过此函数写入的文件上的字符编码由FF_STRF_ENCODE选择。编码错误或输出编码无效的字符将丢失。

f_printf - 写一个格式化的字符串

函数原型

int f_printf (
  FIL* fp,          /* [IN] File object */
  const TCHAR* fmt, /* [IN] Format stirng */
  ...
);

形参
fp
文件指针。
fmt
指向以null“\0”结尾的格式字符串的指针。将不输出终止符字符。

可变参数。
返回值
成功写入字符串后,它返回写入文件的字符编码单元数。当函数由于磁盘已满或错误而失败时,将返回负值。
描述
格式控制指令是标准库的子集,如下所示:

    %[flag][width][precision][size]type

flag
填充选项。A-指定左对齐。0指定零填充。默认设置为右对齐和空格填充。
width
字段的最小宽度,1-99或*。如果生成的字符串的宽度小于指定的值,则rest字段将填充空格或零。指定值来自int类型的参数。
precision
指定小数位数或字符串的最大宽度、.0-.99或。
。若省略数字,则与.0相同。数字的默认设置为6,字符串没有限制。
size
指定整型参数l(长)和ll(长)的大小。如果sizeof(long)==sizeof(int)为真(这是32位系统的典型情况),则长整数参数可以省略前缀l。整数数组的默认大小为int,浮点参数始终假定为double。
type
指定输出格式的类型和参数,如下所示。生成字符串的长度假定int为32位。

在这里插入图片描述

当FatFs配置为Unicode API(FF_LFN_Unicode>=1)时,字符串函数、f_putc、f_puts、f_printf和f_gets函数上的字符编码也会切换为Unicode。多重编码单元中的Unicode字符(如代理项对和多字节序列)不应划分为两个函数调用,否则字符将丢失。FF_STRF_ENCODE选择要通过此函数写入的文件上的字符编码。编码错误或输出编码无效的字符将丢失。

f_tell - 获取当前读/写指针

函数原型

FSIZE_t f_tell (
  FIL* fp   /* [IN] File object */
);

形参
fp
文件指针。
返回值
返回文件的当前读/写指针。
描述
在本版本中,f_tell函数作为宏实现。它没有任何验证和互斥。

#define f_tell(fp) ((fp)->fptr)

f_eof - 文件结尾测试

函数原型

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

形参
fp
文件指针。
返回值
如果读/写指针已到达文件末尾,则f_eof函数返回一个非零值;否则返回零。
描述
在本版本中,此功能作为宏实现。它没有任何验证和互斥。

#define f_eof(fp) ((int)((fp)->fptr == (fp)->fsize))

f_size - 获取文件大小

函数原型

FSIZE_t f_size (
  FIL* fp   /* [IN] File object */
);

形参
fp
文件指针。
返回值
以字节为单位返回文件的大小。
描述
在本版本中,f_size函数作为宏实现。它没有任何验证和互斥。

#define f_size(fp) ((fp)->obj.objsize)

f_error - 测试错误

函数原型

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

形参
fp
文件指针。
返回值
如果发生硬错误,则返回非零值;否则返回零。
描述
在本版本中,此函数作为宏实现。它没有任何验证和互斥。

#define f_error(fp) ((fp)->err)
本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到