天天看點

FatFS使用介紹及示例1. 簡介2. 用法3. 示例4. 檢視虛拟盤資訊5. 注意6. 代碼

1. 簡介

FatFS是一個适用于小型嵌入式系統的通用的FAT/exFAT檔案系統子產品。FatFS是使用ANSI C(C89)進行編寫的,并且分出了磁盤I/O層,是以它是獨立于平台的。不僅僅可以用于各種嵌入式平台,同樣台用于Linux、android、MacOS甚至windows平台。

主要代碼檔案:

  • ff.h和ff.c是檔案系統相關的代碼。
  • diskio.h和diskio.c是磁盤I/O操作接口代碼。
  • ffconf.h是檔案系統版本配置代碼,通過配置來開啟關閉功能,可以根據需要提供更小的代碼空間占用。

2. 用法

本文的内容及示例均是基于ff1.4版本進行的,并且在Windows平台上,基于虛拟磁盤和真實U盤進行測試和驗證的。

2.1. 配置資訊

以下設定為示例使用設定,為了更友善測試,沒有啟用Unicode及多分區功能。

  • #define FF_CODE_PAGE 936 // 如果想支援中文使用此配置
  • #define FF_LFN_UNICODE 0 // 配置是否使用unicode,0表示使用ANSI
  • #define FF_MULTI_PARTITION 0 // 是否啟用多分區,預設不啟用

2.2. 磁盤操作接口

FatFS使用介紹及示例1. 簡介2. 用法3. 示例4. 檢視虛拟盤資訊5. 注意6. 代碼
// 此函數主要完成磁盤裝置的打開(虛拟磁盤檔案的建立打開)
int assign_drives();
// 此函數傳回磁盤是否寫保護狀态
DSTATUS disk_status (BYTE pdrv);
// 此函數的作用是完成擷取磁盤的容量、扇區大小(虛拟磁盤直接寫死即可)
DSTATUS disk_initialize (BYTE pdrv);
// 此函數主要負責讀取磁盤指定位置指定大小的内容
DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count);
// 此函數主要負責往磁盤指定位置寫入指定大小的内容
DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count);
// 此函數主要根據cmd來傳回指定内容,如扇區大小、容量、對齊扇區大小
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
           

2.2.1. 真實磁盤操作接口實作

/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive                                                 */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (
	BYTE pdrv		/* Physical drive nmuber */
)
{
	DSTATUS sta;

	if (WaitForSingleObject(hMutex, 5000) != WAIT_OBJECT_0)
	{
		return STA_NOINIT;
	}

	get_status(pdrv);
	sta = Stat[pdrv].status;

	ReleaseMutex(hMutex);
	return sta;
}



/*-----------------------------------------------------------------------*/
/* Get Disk Status                                                       */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
	BYTE pdrv		/* Physical drive nmuber (0) */
	)
{
	DSTATUS sta;

	sta = Stat[pdrv].status;
	return sta;
}



/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/

DRESULT disk_read (
	BYTE pdrv,			/* Physical drive nmuber (0) */
	BYTE *buff,			/* Pointer to the data buffer to store read data */
	LBA_t sector,		/* Start sector number (LBA) */
	UINT count			/* Number of sectors to read */
)
{
	DWORD nc = 0, rnc;
	DSTATUS res;
	UINT uPartIdx = 0;
	UINT uPartCnt = (count+127) / 128;
	UINT uBuffSct = 128;

	if (Stat[pdrv].status & STA_NOINIT || WaitForSingleObject(hMutex, 3000) != WAIT_OBJECT_0) 
	{
		return RES_NOTRDY;
	}

	nc = (DWORD)count * Stat[pdrv].sz_sector;
	memcpy(Buffer, buff, nc);

	for (; uPartIdx < uPartCnt; uPartIdx++)
	{
		// 如果是最後1份,且是不完整的
		if (uPartIdx == (count / 128))
		{
			uBuffSct = count % 128;
		}

		if (!LogReadFlash(Stat[pdrv].h_drive, sector, uBuffSct, Buffer, 512))
		{
			res = RES_ERROR;
		}
		else
		{
			memcpy(buff + uPartIdx*128*512, Buffer, nc);
			res = RES_OK;
		}
		sector += uBuffSct;
	}

	ReleaseMutex(hMutex);
	return res;
}



/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/

DRESULT disk_write (
	BYTE pdrv,			/* Physical drive nmuber (0) */
	const BYTE *buff,	/* Pointer to the data to be written */
	LBA_t sector,		/* Start sector number (LBA) */
	UINT count			/* Number of sectors to write */
)
{
	DWORD nc = 0, rnc;
	LARGE_INTEGER ofs;
	DRESULT res;

	if (Stat[pdrv].status & STA_NOINIT || WaitForSingleObject(hMutex, 3000) != WAIT_OBJECT_0)
	{
		return RES_NOTRDY;
	}

	res = RES_OK;
	if (Stat[pdrv].status & STA_PROTECT)
	{
		res = RES_WRPRT;
	} 
	else 
	{
		nc = (DWORD)count * Stat[pdrv].sz_sector;
		if (nc > BUFSIZE) res = RES_PARERR;
	}

	/* Physical drives */
	if (pdrv >= MIN_READ_ONLY && pdrv <= MAX_READ_ONLY)
		res = RES_WRPRT;

	if (res == RES_OK)
	{
		UINT uPartIdx = 0;
		UINT uPartCnt = (count+127) / 128;
		UINT uBuffSct = 128;
		memcpy(Buffer, buff, nc);

		for (; uPartIdx < uPartCnt; uPartIdx++)
		{
			// 如果是最後1份,且是不完整的
			if (uPartIdx == (count / 128))
			{
				uBuffSct = count % 128;
			}

			if (!LogWriteFlash(Stat[pdrv].h_drive, sector, uBuffSct, Buffer, 512))
			{
				res = RES_ERROR;
			}

			sector += uBuffSct;
		}
	}

	ReleaseMutex(hMutex);
	return res;
}



/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/

DRESULT disk_ioctl (
	BYTE pdrv,		/* Physical drive nmuber (0) */
	BYTE ctrl,		/* Control code */
	void *buff		/* Buffer to send/receive data */
)
{
	DRESULT res;


	if ((Stat[pdrv].status & STA_NOINIT))
	{
		return RES_NOTRDY;
	}

	res = RES_PARERR;
	switch (ctrl)
	{
	case CTRL_SYNC:			/* Nothing to do */
		res = RES_OK;
		break;

	case GET_SECTOR_COUNT:	/* Get number of sectors on the drive */
		*(LBA_t*)buff = Stat[pdrv].n_sectors;
		res = RES_OK;
		break;

	case GET_SECTOR_SIZE:	/* Get size of sector for generic read/write */
		*(WORD*)buff = Stat[pdrv].sz_sector;
		res = RES_OK;
		break;

	case GET_BLOCK_SIZE:	/* Get internal block size in unit of sector */
		*(DWORD*)buff = SZ_BLOCK;
		res = RES_OK;
		break;

	case 200:				/* Load disk image file to the RAM disk (drive 0) */
		{
			HANDLE h;
			DWORD br;

			if (pdrv == 0) 
			{
				h = CreateFileW(buff, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
				if (h != INVALID_HANDLE_VALUE)
				{
					if (ReadFile(h, RamDisk, SZ_RAMDISK * 1024 * 1024, &br, 0)) 
					{
						res = RES_OK;
					}
					CloseHandle(h);
				}
			}
		}
		break;
	}

	return res;
}
           

2.2.2. 虛拟磁盤操作接口實作

int get_status (
	BYTE pdrv
)
{
	volatile STAT *stat = &Stat[pdrv];

	/* Get drive size */
	stat->status = STA_NOINIT;
	stat->sz_sector = 512;
	stat->n_sectors = 15761504;
	if (stat->sz_sector < FF_MIN_SS || stat->sz_sector > FF_MAX_SS) 
		return 0;

	/* Get write protect status */
	stat->status = 0;
	if (pdrv >= MIN_READ_ONLY && pdrv <= MAX_READ_ONLY) stat->status = STA_PROTECT;

	return 1;
}


/*--------------------------------------------------------------------------

   Public Functions

---------------------------------------------------------------------------*/
#define FILENAME "e:\\Virtual.img"

/*-----------------------------------------------------------------------*/
/* Initialize Windows disk accesss layer                                 */
/*-----------------------------------------------------------------------*/

int assign_drives (void)
{
	BYTE pdrv = 0;
	HANDLE h;
	DWORD dwRet = 0;
	OSVERSIONINFO vinfo = { sizeof (OSVERSIONINFO) };

	hMutex = CreateMutex(0, 0, 0);
	if (hMutex == INVALID_HANDLE_VALUE) 
		return 0;

	Buffer = VirtualAlloc(0, BUFSIZE, MEM_COMMIT, PAGE_READWRITE);
	if (!Buffer) return 0;

	RamDisk = VirtualAlloc(0, SZ_RAMDISK * 0x100000, MEM_COMMIT, PAGE_READWRITE);
	if (!RamDisk)
		return 0;

	Stat[0].h_drive = fopen(FILENAME, "w+");
	if (!Stat[0].h_drive) 
	{
		printf(__FILE__":%d\n", __LINE__);
		printf(FILENAME" open err!\n");
		return RES_NOTRDY;
	}

	wprintf(L"PD#%u <== %s", 0, "virtual disk");
	if (get_status(0))
	{
		wprintf(L" (%uMB, %u bytes * %I64u sectors)\n", (UINT)((LONGLONG)Stat[pdrv].sz_sector * Stat[pdrv].n_sectors / 1024 / 1024), Stat[pdrv].sz_sector, (QWORD)Stat[pdrv].n_sectors);
	} 
	else
	{
		wprintf(L" (Not Ready)\n");
	}

	Drives = 0;
	return 0;
}



/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive                                                 */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (
	BYTE pdrv		/* Physical drive nmuber */
)
{
	DSTATUS sta;

	if (WaitForSingleObject(hMutex, 5000) != WAIT_OBJECT_0)
	{
		return STA_NOINIT;
	}

	get_status(pdrv);
	sta = Stat[pdrv].status;

	ReleaseMutex(hMutex);
	return sta;
}


/*-----------------------------------------------------------------------*/
/* Get Disk Status                                                       */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
	BYTE pdrv		/* Physical drive nmuber (0) */
	)
{
	DSTATUS sta;

	sta = Stat[pdrv].status;

	return sta;
}


/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/

DRESULT disk_read (
	BYTE pdrv,			/* Physical drive nmuber (0) */
	BYTE *buff,			/* Pointer to the data buffer to store read data */
	LBA_t sector,		/* Start sector number (LBA) */
	UINT count			/* Number of sectors to read */
)
{
	DWORD nc, rnc;
	LARGE_INTEGER ofs;
	DSTATUS res = 0;
	DWORD ulSeek = 0;
	unsigned long nRead = 0;
	int nSeekRes = 0;

	ulSeek = sector * 512;

	nSeekRes = fseek(Stat[pdrv].h_drive, ulSeek, SEEK_SET);
	nRead = fread(buff, 512, count, Stat[pdrv].h_drive);
	if (nSeekRes || nRead == 0) {
		printf(__FILE__":%d\n", __LINE__);
		printf("read disk err!\n");
		return RES_ERROR;
	}

	return res;
}


/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/

DRESULT disk_write (
	BYTE pdrv,			/* Physical drive nmuber (0) */
	const BYTE *buff,	/* Pointer to the data to be written */
	LBA_t sector,		/* Start sector number (LBA) */
	UINT count			/* Number of sectors to write */
)
{
	DWORD nc = 0, rnc;
	LARGE_INTEGER ofs;
	DRESULT res;
	DWORD ulSeek = 0;
	unsigned long nRead = 0;
	int nSeekRes = 0;

	ulSeek = sector * 512;

	res = RES_OK;
	if (Stat[pdrv].status & STA_PROTECT)
	{
		res = RES_WRPRT;
	} 
	else 
	{
		nc = (DWORD)count * Stat[pdrv].sz_sector;
		if (nc > BUFSIZE) res = RES_PARERR;
	}

	nSeekRes = fseek(Stat[pdrv].h_drive, ulSeek, SEEK_SET);
	nRead = fwrite(buff, 512, count, Stat[pdrv].h_drive);
	if (nSeekRes || nRead == 0)
	{
		printf(__FILE__":%d\n", __LINE__);
		printf("read disk err!\n");
		return RES_ERROR;
	}

	return res;
}


/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/

DRESULT disk_ioctl (
	BYTE pdrv,		/* Physical drive nmuber (0) */
	BYTE ctrl,		/* Control code */
	void *buff		/* Buffer to send/receive data */
)
{
	DRESULT res;

	res = RES_PARERR;
	switch (ctrl)
	{
	case CTRL_SYNC:			/* Nothing to do */
		res = RES_OK;
		break;

	case GET_SECTOR_COUNT:	/* Get number of sectors on the drive */
		*(LBA_t*)buff = Stat[pdrv].n_sectors;
		res = RES_OK;
		break;

	case GET_SECTOR_SIZE:	/* Get size of sector for generic read/write */
		*(WORD*)buff = Stat[pdrv].sz_sector;
		res = RES_OK;
		break;

	case GET_BLOCK_SIZE:	/* Get internal block size in unit of sector */
		*(DWORD*)buff = SZ_BLOCK;
		res = RES_OK;
		break;

	case 200:				/* Load disk image file to the RAM disk (drive 0) */
		{
			HANDLE h;
			DWORD br;

			if (pdrv == 0) 
			{
				h = CreateFileW(buff, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
				if (h != INVALID_HANDLE_VALUE)
				{
					if (ReadFile(h, RamDisk, SZ_RAMDISK * 1024 * 1024, &br, 0)) 
					{
						res = RES_OK;
					}
					CloseHandle(h);
				}
			}
		}
		break;
	}

	return res;
}
           

2.3. FatFS常用接口

FatFS應用接口,主要分四大類:

2.3.1. 檔案操作接口

  • f_open -建立或打開檔案,可設定不同讀寫屬性。
  • f_close - 關閉打開的檔案。- f_read - 讀取檔案。
  • f_write - 寫檔案。
  • f_lseek - 移動目前檔案操作指針到指定位置。
  • f_sync - 将緩存立即寫入裝置,需要配置CTRL_SYNC控制碼。
  • - f_forward - 帶回調函數的讀取檔案内容接口。
  • f_tell - 擷取目前檔案指針。
  • f_eof - 測試是否到檔案末尾。
  • f_size - 擷取檔案大小。
  • f_error - 測試是否出現錯誤。

2.3.2. 目錄操作接口

  • f_opendir - 打開指定目錄。
  • f_closedir - 關閉指定目錄。
  • f_readdir - 讀取目錄的内容,可以判斷是否為目錄以及相關屬性等。
  • f_findfirst - 開始周遊目錄,目錄可以使用通配符描述。
  • f_findnext - 讀取下一個目标。

2.3.3. 檔案和目錄管理接口

  • f_stat - 檢測檔案或子目錄是否存在。
  • f_unlink - 删除檔案或子目錄。
  • f_rename - 重命名或移動檔案或子目錄。
  • f_chmod - 改變檔案或子目錄屬性。
  • f_utime - 改變檔案或子目錄時間戳。
  • f_mkdir - 建立子目錄。
  • f_chdir - 改變目前目錄。
  • f_chdrive - 改變目前驅動器号。
  • f_getcwd - 擷取目前驅動器号。

2.3.4. 卷管理和系統配置

  • f_mount - 注冊和反注冊指定卷的工作區,其作用主要是完成卷(檔案系統相關參數)和指定磁盤的對應關系。FatFS預設是使用磁盤号與檔案系統相對應,也可以使用自定義卷名與檔案系統相關聯。另外此函數還會調用磁盤初始化接口來完成磁盤的打開操作。
  • f_mkfs - 對指定的卷(根據磁盤名或卷名)來進行指定類型的格式化操作。
  • f_fdisk - 對指定的實體裝置建立多個分區。
  • f_getfree - 擷取指定卷的空閑空間。
  • f_getlabel - 擷取卷标。
  • f_setlabel - 裝置卷票。
  • f_setcp - 設定活動代碼頁。

3. 示例

示例完全基于ff1.4版本,隻修改磁盤I/O接口,完全不修改ff.c代碼。

3.1. 格式化

  1. 初始化

    調用assign_drives函數完成初始化,即打開指定裝置(實體裝置或邏輯裝置)。

  2. 挂載

    f_mount用來挂載,其作用主要是完成卷(檔案系統相關參數)和指定磁盤的對應關系。

  3. 設定參數

    n_fat預設為1,Windows下通用設定為2。align對齊預設是256。m_root預設為0。au_size預設根據容量計算。

    FatFS使用介紹及示例1. 簡介2. 用法3. 示例4. 檢視虛拟盤資訊5. 注意6. 代碼
  4. 格式化

    FatFs有一個全局變量FatFs[FF_VOLUMES],FF_VOLUMES預設為8。是以FatFS預設隻能挂載8個卷。如果想同時支援更多盤,FF_VOLUMES宏需要相應的修改。

  5. 代碼
// 3就是裝置号,在FatFS中也被稱為邏輯驅動器号,預設不填寫則為0
	TCHAR filePath[] = "3:\\hello.txt";
	MKFS_PARM opt = {0};
	FATFS fsEx = {0};
	FRESULT fRet = FR_OK;
	assign_drives('j', 3);	

	f_mount(&fsEx, "3:", 0);

	opt.fmt = FM_EXFAT;
	opt.n_fat = 2;
	fRet = f_mkfs("3:", &opt, workBuff, sizeof(workBuff));
           

3.2. 讀寫檔案

  1. 初始化

    調用assign_drives函數完成初始化,即打開指定裝置(實體裝置或邏輯裝置)。

  2. 挂載

    f_mount用來挂載,其作用主要是完成卷(檔案系統相關參數)和指定磁盤的對應關系。

  3. 打開檔案

    打開指定檔案,傳回一個檔案屬性清單變量用來寫讀關閉檔案。

  4. 寫檔案

    和Windows寫檔案差不多,詳細示例

  5. 讀檔案

    和Windows讀檔案操作類似,詳細示例

  6. 關閉檔案

    關閉檔案的一個重要作用是保證将緩存寫入裝置(直接裝置或虛拟裝置)

  7. 示例
FIL fil = {0};
	FRESULT res = FR_OK;
	UINT bw = 0;
	BYTE buff[1024] = {0};

	res = f_open(&fil, pFilePath, FA_CREATE_NEW | FA_WRITE);
	if (res) 
	{
		printf("f_open hello.txt err\n");
		return res;
	}

	f_write(&fil, "Hello, World!\n", 15, &bw);
	if (bw != 15) 
	{
		printf("f_write hello.txt err\n");
		f_close(&fil);
		return 1;
	}
	f_close(&fil);

	res = f_open(&fil, pFilePath, FA_READ | FA_OPEN_EXISTING);
	if (res)
	{
		printf("f_open hello.txt err\n");
		return res;
	}

	memset(buff, 0, sizeof(buff));
	res = f_read(&fil, buff, 15, &bw);
	if (res) 
	{
		printf("f_read err\n");
		f_close(&fil);
		return res;
	}
	printf("buff: %s", buff);
           

3.3. 讀寫目錄

  1. 初始化

    調用assign_drives函數完成初始化,即打開指定裝置(實體裝置或邏輯裝置)。

  2. 挂載

    f_mount用來挂載,其作用主要是完成卷(檔案系統相關參數)和指定磁盤的對應關系。

  3. 建立目錄

    f_mkdir的參數和Windows類似,隻需要目錄名,預設目前目錄。

  4. 打開目錄

    f_opendir打開指定目錄,傳回一個目錄辨別供讀目錄使用。

  5. 讀取目錄

    讀取目錄資訊,包括是否目錄、各種目錄屬性。

  6. 關閉目錄
  7. 建立打開示例
UINT bw = 0;
	FIL fil = {0};
	TCHAR buff[1024] = {0};
	DIR dir = {0};
	FRESULT res = FR_OK;
	res = f_mkdir("3:\\ABC");
	if (res) 
	{
		printf("f_open hello.txt err\n");
		return res;
	}
	res = f_opendir(&dir, "3:\\ABC");
	if (res) 
	{
		printf("f_open hello.txt err\n");
		return res;
	}
	res = f_mkdir("3:\\ABC\\A");
	if (res) 
	{
		printf("f_open hello.txt err\n");
		return res;
	}
	res = f_opendir(&dir, "3:\\ABC\\A");
	if (res) 
	{
		printf("f_open hello.txt err\n");
		return res;
	}
	res = f_mkdir("3:\\ABC\\B");
	if (res) 
	{
		printf("f_open hello.txt err\n");
		return res;
	}
	res = f_opendir(&dir, "3:\\ABC\\B");
	if (res) 
	{
		printf("f_open hello.txt err\n");
		return res;
	}
	res = f_mkdir("3:\\ABC\\B\\C");
	if (res) 
	{
		printf("f_open hello.txt err\n");
		return res;
	}
	res = f_opendir(&dir, "3:\\ABC\\B\\C");
	if (res) 
	{
		printf("f_open hello.txt err\n");
		return res;
	}
	f_closedir(&dir);

	res = f_open(&fil, "3:/ABC/B/a.txt", FA_CREATE_NEW | FA_WRITE);
	if (res) 
	{
		printf("f_open hello.txt err\n");
		return res;
	}

	f_write(&fil, "Mike say:Hello, World!\n", 24, &bw);
	if (bw != 24) 
	{
		printf("f_write hello.txt err\n");
		f_close(&fil);
		return 1;
	}

	f_close(&fil);

	res = f_open(&fil, "3:/ABC/B/a.txt", FA_READ | FA_OPEN_EXISTING);
	if (res)
	{
		printf("f_open hello.txt err\n");
		return res;
	}
	memset(buff, 0, sizeof(buff));
	res = f_read(&fil, buff, 24, &bw);
	if (res) 
	{
		printf("f_read err\n");
		f_close(&fil);
		return res;
	}
	printf("buff: %s", buff);
	f_close(&fil);
           
  1. 周遊目錄示例
FRESULT scan_files (
	CHAR* path		/* Pointer to the path name working buffer */
)
{
	DIR dir;
	FRESULT res;
	int i;

	if ((res = f_opendir(&dir, path)) == FR_OK) 
	{
		i = strlen(path);
		while (((res = f_readdir(&dir, &Finfo)) == FR_OK) && Finfo.fname[0])
		{
			if (Finfo.fattrib & AM_DIR) 
			{
				AccDirs++;
				*(path+i) = L'/';
				strcpy(path+i+1, Finfo.fname);
				printf("%s\n", path);
				res = scan_files(path);
				*(path+i) = L'\0';
				if (res != FR_OK) 
					break;
			} 
			else
			{
				AccFiles++;
				AccSize += Finfo.fsize;
				printf("%s\n", Finfo.fname);
			}
		}
		f_closedir(&dir);
	}

	return res;
}
           

3.4. 多分區

多分區需要啟用宏FF_MULTI_PARTITION。

int TestMultiParition()
{
#if FF_MULTI_PARTITION
	FRESULT fRet = FR_OK;
	MKFS_PARM opt = {0};
	LBA_t plist[] = {3000*2048, 100};  /* Divide the drive into two partitions */
	/* {0x10000000, 100}; 256M sectors for 1st partition and left all for 2nd partition */
	/* {20, 20, 20, 0}; 20% for 3 partitions each and remaing space is left not allocated */

	f_fdisk(0, plist, workBuff);                    /* Divide physical drive 0 */
	opt.fmt = FM_FAT32;
	opt.n_fat = 2;
	fRet = f_mkfs("0:", &opt, workBuff, sizeof(workBuff)); /* Create FAT volume on the logical drive 0 */
	fRet = f_mkfs("1:", &opt, workBuff, sizeof(workBuff)); /* Create FAT volume on the logical drive 1 */
#endif
	return 0;
}
           

4. 檢視虛拟盤資訊

我們可以通過虛拟盤将檔案系統及相關資訊寫入到Windows的檔案中,用檔案來模拟FatFS的移植。建立format.img檔案,将diskio的相關接口均實作到此檔案中。并且通過DiskGunius工具提供的打開虛拟磁盤檔案,可以檢視相關資訊。DiskGunius支援FAT32和exFAT檔案系統。

FatFS使用介紹及示例1. 簡介2. 用法3. 示例4. 檢視虛拟盤資訊5. 注意6. 代碼

5. 注意

  • 多盤需要考慮修改FatFs數組的大小。
  • 讀寫檔案時,需要考慮記憶體使用情況。

6. 代碼

Windows下基于檔案仿真FatFS

基于Windows下的真實U盤的FatFS