Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Кармин Новиелло - Освоение STM32.pdf
Скачиваний:
2739
Добавлен:
23.09.2021
Размер:
47.68 Mб
Скачать

Файловая система FAT

705

25.1.2. Наиболее важные структуры и функции FatFs

А теперь мы проанализируем наиболее важные структуры и функции, предоставляемые библиотекой FatFs для управления дисками FAT7.

25.1.2.1. Монтирование файловой системы

Перед обращением к любому файлу или каталогу в файловой системе нам необходимо смонтировать8 ее, используя функцию:

FRESULT f_mount(FATFS *fs, const TCHAR *path, BYTE opt);

fs – экземпляр структуры Си FATFS, которая хранит информацию о логическом диске (разделе); path – указатель на строку с завершающим нулем, который указывает на логический диск (подробнее об этом позже); opt может принимать значение 0 для того, чтобы отложить монтирование файловой системы до первого доступа к диску (например, открытие файла или каталога), или же может принимать значение 1 для немедленного монтирования логического диска. Приложение не должно изменять какой-либо из элементов структуры FATFS, иначе исходный логический/физический диск может быть безвозвратно поврежден.

Формат параметра path аналогичен спецификации имен дисков в операционной системе Windows, при этом он может принимать вид N:/, где N – число, начинающееся с 0, которое однозначно идентифицирует логический диск. По умолчанию на каждом физическом диске может быть только один логический диск (то есть раздел). Это означает, что, если наш диск имеет более одного раздела, то только первый из них в таблице разделов будет смонтирован и ассоциирован с логическим диском. Вместо этого, установив макрос _MULTI_PARTITION=1 в файле ffconf.h, библиотека FatFs ассоциирует логический диск с каждым разделом на физическом диске. Если номер диска опущен, предполагается, что номер диска является диском по умолчанию (диск 0 на текущем диске). Таким образом, мы можем передать параметру path символы косой черты или обратной косой черты (\ или /) или даже задать указать на NULL строку. Например, следующий код форсирует монтирование первого раздела на физическом диске:

FATFS fs; f_mount(&fs, "/", 1);

Если логический диск смонтируется корректно, то функция f_mount() возвратит значение FR_OK. В противном случае может быть возвращен ряд условий ошибок

(FR_INVALID_DRIVE, FR_DISK_ERR, FR_NOT_READY, FR_NO_FILESYSTEM).

25.1.2.2. Открытие файлов

После того, как диск смонтирован, мы можем открыть файл с помощью функции:

7Полная версия API библиотеки FatFS документирована на веб-сайте Чана.

8Монтирование (mounting) диска – это операция, выполняемая драйвером файловой системы, которая, по существу, состоит из сбора всей логической информации, ассоциированной с физическим диском или его частью (количество разделов, размер раздела, размер кластеров, количество кластеров и т. д.). Перед монтированием файловой системы невозможно использовать какие-либо из ее примитивов (каталоги, файлы и т. д.).

Файловая система FAT

706

FRESULT f_open(FIL* fp, const TCHAR* path, BYTE mode);

fp – это экземпляр структуры Си FIL, в которой содержится информация об открытом файле (его имени, размере, начальном кластере и т. д.); path соответствует пути файловой системы для доступа к файлу (подробнее об этом скоро); mode определяет тип доступа и метод открытия файла, и он может принимать значение из таблицы 1.

 

Таблица 1: Список методов открытия файлов

Значение

Описание

 

 

FA_READ

Задает объекту доступ на чтение. Данные можно прочитать из файла.

FA_WRITE

Задает объекту доступ на запись. Данные могут быть записаны в файл.

 

Его можно комбинировать (через логическое ИЛИ) с FA_READ для задания

 

доступа на чтение и на запись.

FA_OPEN_EXISTING

FA_CREATE_NEW

FA_CREATE_ALWAYS

FA_OPEN_ALWAYS

FA_OPEN_APPEND

Открывает файл. Функция не выполняется, если файл не существует. (По умолчанию)

Создает новый файл. Функция f_open() возвращает FR_EXIST, если файл уже существует.

Создает новый файл. Если файл существует, он будет усечен и перезаписан.

Открывает существующий файл. Если его нет, то будет создан новый файл.

То же, что и FA_OPEN_ALWAYS, за исключением того, что указатель чтения/записи устанавливается в конец файла.

Что касается пути к файлу, то он соответствует полному пути файловой системы к файлу, включая его имя. Например, 0:\dir1\filename.txt открывает файл с именем filename.txt внутри каталога с именем dir1 на первом логическом диске. Если наше приложение использует лишь один логический диск, то мы можем просто указать путь в другом виде: \dir1\filename.txt. Обратите внимание, что FatFs может обрабатывать пути как в Windows, так и в UNIX стиле. Таким образом, следуя предыдущему примеру, мы также можем указать путь в эквивалентном виде: 0:/dir1/filename.txt.

Если файл открывается корректно, то функция f_open() возвращает значение FR_OK. В противном случае может быть возвращен ряд условий ошибки (подробнее о них см. в документации9).

25.1.2.3. Чтение и запись файла

После открытия файла мы можем читать из него данные или записывать новые данные в соответствии с выбранным режимом открытия файла. Для этого в библиотеке FatFs предусмотрены следующие функции:

FRESULT f_read(FIL* fp, void* buff, UINT btr, UINT* br);

FRESULT f_write(FIL* fp, const void* buff, UINT btr, UINT* br);

fp соответствует дескриптору файла, переданному в функцию f_open(); buff – это указатель на буфер, содержащий данные для чтения из файла или для сохранения в нем; btw

9 http://www.elm-chan.org/fsw/ff/en/open.html

Файловая система FAT

707

указывает количество байтов для чтения/записи; bw соответствует количеству успешно прочитанных/записанных байтов.

В следующем примере показано применение рассмотренных ранее функций. Это не что иное, как процедура копирования файлов.

1

#define BUF_LEN 2048

 

 

2

 

 

 

3

FRESULT copy_file (char *srcPath, char *dstPath) {

4

FATFS fs;

/*

Объект файловой системы, соответствующий логическому диску */

5

FIL fsrc, fdst;

/*

Объекты файлов */

6

BYTE buffer[BUF_LEN]; /*

Буфер копирования файлов */

7

FRESULT fr;

/*

Общий код результата выполнения функций FatFs */

8

UINT br, bw;

/*

Счетчик чтения/записи файла */

9

 

 

 

10/* Монтирование файловой системы */

11f_mount(&fs[0], "0:", 0);

12

13/* Открытие исходного файла */

14fr = f_open(&fsrc, srcPath, FA_READ);

15if (fr) return (int)fr;

16

17/* Создание целевого файла */

18fr = f_open(&fdst, dstPath, FA_WRITE | FA_CREATE_ALWAYS);

19if (fr) return (int)fr;

20

21/* Копирование исходного файла в целевой файл */

22while(1) {

23/* Чтение 'BUF_LEN' Байт из исходного файла */

24fr = f_read(&fsrc, buffer, BUF_LEN, &br);

25if (fr != FR_OK || br == 0) break; /* Условие ошибки или EOF */

26/* Запись прочитанных данных в целевой файл */

27fr = f_write(&fdst, buffer, br, &bw);

28if (fr != FR_OK || bw < br) break; /* Ошибка или диск заполнен */

29}

30

31/* Закрытие открытых файлов */

32f_close(&fsrc);

33f_close(&fdst);

34

35/* Размонтирование тома */

36f_mount(NULL, "0:", 0);

37

38return fr;

39}

25.1.2.4. Создание и открытие каталога

Библиотека FatFs позволяет легко управлять файлами, а также каталогами. Чтобы создать новый каталог, мы можем воспользоваться функцией:

Файловая система FAT

708

FRESULT f_mkdir(const TCHAR* path);

которая принимает полный путь к создаваемому каталогу. Например, предположим, что наша файловая система уже хранит каталог с именем dir1 в своем корне, тогда для создания подкаталога мы можем передать строку "0:/dir1/subdir1", чтобы создать в нем подкаталог.

Чтобы открыть уже существующий каталог, мы можем использовать функцию:

FRESULT f_opendir(DIR* dp, const TCHAR* path);

dp – экземпляр структуры Си DIR, представляющий собой дескриптор открытого каталога; path – полный путь к каталогу, который мы хотим открыть. Если функцией f_opendir()возвращается допустимый дескриптор, то мы можем прочитать его содержимое с помощью функции:

FRESULT f_readdir(DIR* dp, FILINFO* fno);

dp – экземпляр, соответствующий каталогу, открытому с помощью функции f_opendir(); fno – экземпляр структуры FILINFO, который содержит информацию о текущем элементе в каталоге. Функция f_readdir() работает следующим образом. После открытия каталога мы вызываем f_readdir() до тех пор, пока она не вернет значение, отличное от FR_OK (в случае возникновения ошибки), или пока запись fno.fname не станет равной нулевому указателю (null). Это последнее условие означает, что мы достигли конца каталога и больше не осталось элементов (файлов или каталогов) для извлечения.

Структура FILINFO определена следующим образом:

typedef struct {

 

 

DWORD fsize;

/* Размер файла */

 

WORD fdate;

/* Дата последнего изменения

*/

WORD ftime;

/* Время последнего изменения */

BYTE fattrib;

/* Атрибут */

 

TCHAR fname[13];

/* Краткое имя файла (формат

8.3) */

#if _USE_LFN

 

 

TCHAR* lfname;

/* Указатель на буфер LFN */

 

UINT lfsize;

/* Размер буфера LFN в TCHAR

*/

#endif

 

 

} FILINFO;

 

 

Давайте разберем поля этой структуры.

fsize: хранит размер файла в байтах. Бессмысленно, если объект является катало-

гом.

fdate: указывает дату, когда файл был изменен или когда каталог был создан, и

имеет следующую структуру

бит [15:9]: год, начиная с 1980 (0..127)

бит [8:5]: месяц (1..12)

бит [4:0]: день (1..31)

Файловая система FAT

709

ftime: указывает время, когда файл был изменен или когда каталог был создан, и

имеет следующую структуру

бит [15:11]: час (0..23)

бит [10:5]: минута (0..59)

бит [4:0]: секунда / 2 (0..29)

fattrib: соответствует атрибуту файла/каталога, который представляет собой ком-

бинацию атрибутов, перечисленных в таблице 2.

fname: строка с завершающим нулем соответствует имени файла/каталога в фор-

мате FAT 8:3. Строка NULL сохраняется, если больше нет элементов для чтения, и это указывает на недопустимую структуру.

lfname: строка с завершающим нулем соответствует имени файла/каталога, когда

включена поддержка длинных имен файлов (макрос _USE_LFN != 0). Подробнее об этом позже.

Таблица 2: Список атрибутов файла/каталога

Атрибут файла/каталога

Описание

 

 

AM_RDO

Только для чтения

AM_ARC

Архивный

AM_SYS

Системный

AM_HID

Скрытый

В следующем примере показана процедура, которая осуществляет проход по файловой системе на глубину в одно вложение, выводя имена файлов и папок с помощью процедуры trace_printf(). Процедура использует функции f_opendir() и f_readdir() для получения содержимого каждого каталога. Макрос _USE_LFN позволяет корректно обрабатывать длинные имена файлов. Его использование будет объяснено в следующем параграфе.

1FRESULT scan_files (TCHAR* path) {

2FRESULT res;

3DIR dir;

4UINT i;

5static FILINFO fno;

6static TCHAR lfname[_MAX_LFN];

7TCHAR *fname;

8

9res = f_opendir(&dir, path); /* Открыть каталог */

10if (res == FR_OK) {

11while(1) {

12#if _USE_LFN > 0

13

fno.lfname = lfname;

14

fno.lfsize = _MAX_LFN - 1;

15

#endif

 

16

/*

Прочитать элемент каталога */

17

res = f_readdir(&dir, &fno);

18

/*

Прервать цикл при ошибке или конце каталога */

19

if

(res != FR_OK || fno.fname[0] == 0) break;

20

#if _USE_LFN >

0

21

fname = *fno.lfname ? fno.lfname : fno.fname;