4.3   Читання вмісту директорія. Пошук файлів

При написанні програм часто необхідно прочитати вміст директорія для визначення того, які файли там зареєстровані. На жаль, директорій MS-DOS не може бути відкритий як звичайний регулярний файл для читання або запису. У цім зв’язку доводиться використовувати спеціальні функції Turbo С, прототипи яких наведені у файлі <dir.h>.

#include <dir.h>
int findfirst( const char *filename, struct ffblk *ffblk, inl attrib )

Викликає функцію MS-DOS АН=4Eh для одержання інформації про перший файл (у тому числі і про директорію), ім’я якого відповідає файлу, заданому в рядку filename, а атрибути - атрибутам, заданим параметром attrib. Аргумент filename указує на ASCIIZ-рядок вигляду

[накопичувач] [маршрут] ім’я_файлу [.розширення]

Ім’я файлу і розширення можуть включати спеціальні символи-шаблони “?” і “*”, що задають відповідно пошук збігу по одному будь-якому символу або групі будь-яких символів. Значення attrib може бути утворено операцією порозрядного АБО констант із Табл. 9. Якщо не заданий накопичувач або маршрут, MS-DOS приймає поточний накопичувач і поточні директорії. Якщо збіг знайдений, функція повертає 0 і заповнює структурну перемінну по шаблону ffblk, на якій указує ffblk. При відсутності збігу або у випадку помилки повертається -1 і в зовнішню змінну errno записується код помилки. Функція встановлює errno в значення ENOENT, якщо запитаний файл не існує, або в значення ENMFILE, повідомляючи, що більше задовольняючих критерію пошуку файлів немає. Шаблон структури ffblk включає поля, що входять у керуючий блок MS-DOS ‑ блок керування файлом, або FCB (File Control Block). Порядок розташування полів у ffblk Turbo С відрізняється від структури FCB.

struct ffblk {
   char ff_reserved[ 21 ]; /* зарезервовано для MS-DOS */;
   char ff_attrib;                /* атрибут з елементу директорія */
   unsigned ff_ftime;          /* поле часу з елементу директорія */
   unsigned ff_fdate;          /* поле дати з елементу директорія */
   long ff_fsize;                  /* поле розміру файла з елементу директорія */
   char ff_name[ 13 ];       /*ASCIIZ- рядок з ім’ям і розширенням байлу
                                         з елементу директорія, включаючи символ “.”
                                         який розділяє імя та розширення файлу */
}

Після успішного виконання функції, поле ff_name містить ASCIIZ-рядок імені і розширення файлу, розділені символом ‘.’, файлу, який задовольняє заданим критеріям пошуку. Байт атрибута цього файлу копіюється в поле ff_attrib. Поле ff_fsize містить розмір звичайного файлу. Для директорія і мітки тому це поле дорівнює 0. Поля ff_ftime і ff_fdate повідомляють відповідно час і дату останньої модифікації файлу. Структура полів відповідає розглянутій в розділі 2.3.

#include <dir.h>
int findnext( struct ffblk *ffblk )

Продовжує пошук збігів, початий функцією findfirst. Якщо збіг знайдений, функція повертає 0 і заповнює структурну змінну по шаблону ffblk, на якій вказує ffblk. При відсутності збігів або у випадку помилки повертається -1 і в зовнішню змінну ernno записується код помилки, функція встановлює ernno у значення ENOENT, якщо запитаний файл не існує, або в значення ENMFILE, повідомляючи, що задовольняючому критерію пошуку файлів більше немає.

#include <dir.h>
void fnmerge( char *path, const char *drive, const char *dir,
                                const char *name, const char *ext )

В області пам’яті, на якій указує path, будується ASCIIZ-рядок специфікації файлу по наданих компонентах. Компоненти специфікації задаються покажчиками на ASCIIZ-рядки:

drive - накопичувач, наприклад “a:”;
dir - маршрут директорія;
name - ім’я файлу;
ext - розширення імені файлу.

#include <dir.h>
inl fnsplit( const char *path, char *drive, char *dir,
                            char *name, char *ext )

“Розбирає” специфікацію файлу, задану ASCIIZ-рядком, на який посилається path. У результаті розбору породжуються ASCIIZ-рядки:

drive - накопичувач, наприклад "а:";
dir - маршрут директорія;
name - ім’я файлу;
ext розширення імені файлу.

Функція повертає ціле число, утворене об’єднанням по АБО символічних констант:

WILDCARDS

-         специфікація містить символи шаблону “?” і “*”;

EXTENSION

-         специфікація містить розширення імені файлу;

FILENAME

-         специфікація містить ім’я файлу;

DIRECTORY

-         специфікація містить субдиректорій;

DRIVE

-         специфікація містить букву накопичувача.

#include <dir. h>
char *searchpath( const char *file )

Виконує пошук файлу, ім’я якого задає file. Пошук файлу виконується спочатку в поточну директорії, а потім у всіх директоріях, зазначених рядком середовища PATH. У випадку успіху функція повертає покажчик на внутрішню статичну область пам’яті, у якій записується повна специфікація файлу. У протилежному випадку повертає NULL.

Наведемо приклад програми, що виводить на екран інформацію про всі директорії і файли, що відповідають заданому шаблону. Шаблон задається першим аргументом командного рядка при запуску програми у виді

[ накопичувач ] [ маршрут ] ім’я_файлу [ розширення ]

Ім’я_файлу і розширення можуть містити символи “*” і “?”.

/*L4_2.C*/
#include <stdio.h>
# include <string.h>
#include <ctype.h>
#include <dos.h>
# include <dir.h>
void print_element( struct ffblk* );
int main( int argc, char **argv ) {
  int new_drive;
  static struct ffblk my;
  iff( argc<2) {              /* Чи всі аргументи задані? */
     printf( “\a%s\n”, “Використання програми:L4_2 "\
       “[накопичувач]:маршрут\[шаблон_выбору_файлів]” );
     return(1);
  }
  /* Перевірка завдання накопичувача. */
  if( strchr( argv[ 1 ], ( int )’:’ ) != NULL ) {
     new_drive = toupper((int)*argv[1])-’A’;
     if( setdisk(0xf) < new_drive) {
        printf( “\a%s\n”, “Задано неіснуючий накопичувач”);
        return(2);
     }
  }
  printf(“Элементи, що задовольняють шаблону пошуку %s\n\n",
             argv[1]);
  /* Перша спроба знайти збіг */
  if( findfirst( argv[1], &my, 0xff )== -1 ) {
     printf( “\a%s\n”, “Немає таких файлів або директорій” );
     return(3);
  } print_element( &my );
  /* Цикл пошуку елементів, що задовольняють шаблону */
  while( findnext( &my ) == 0)
     print_element( &my);
  return(0);
}

/* Внутрішня функція круку елементу директорія. */
void print_element( struct ffblk *my ) {
  printf(“%-12s%9lu байт”, my->ff_name, my ->ff_fsize);
  if( my->ff_attrib & FA_LABEL )
     printf( “%s”, “Мітка тому” );
  if( my->ff_attrib & FA_DIREC )
     printf( “%s”, “Директорій” );
  if( ту->ff_attrib & FA_ARCH )
     printf( “%s”, “Архівний” );
  if( my->ff_attrib & FA_RDONLY )
     printf( “%s”, “Тільки що читається” );
  if( my->ff_attrib & FA_SYSTEM )
     printf(“%s”, “Системний” );
  if( my->ff_attrib & FA_HIDDEN)
     printf( “%s”, “Що приховується”);
  putchar( ‘\n’ );
}

Програма виконує дії, подібні команді dir COMMAND.COM, проте при цьому не виконується інтерпретація полів дати і часу елементу директорія. Відсутнє також опрацювання ключів /w, /p та ін.