Выбрать главу

  ok = TraverseDirectory(pFileName, MAX_OPTIONS, Flags) && ok;

  SetCurrentDirectory(CurrPath);

  /* Восстановить каталог. */

 }

 return ok ? 0 : 1;

}

static BOOL TraverseDirectory(LPCTSTR PathName, DWORD NumFlags, LPBOOL Flags)

/* Обход дерева каталогов; выполнить функцию ProcessItem для каждого случая совпадения. */

/* PathName: относительное или абсолютное имя просматриваемого каталога.*/

{

 HANDLE SearchHandle;

 WIN32_FIND_DATA FindData;

 BOOL Recursive = Flags[0];

 DWORD FType, iPass;

 TCHAR CurrPath[MAX_PATH + 1];

 GetCurrentDirectory(MAX_PATH, CurrPath);

 for (iPass = 1; iPass <= 2; iPass++) {

  /* Проход 1: вывод списка файлов. */

  /* Проход 2: обход дерева каталогов (если задана опция –R). */

  SearchHandle = FindFirstFile(PathName, &FindData);

  do {

   FType = FileType(&FindData);

   /* Файл или каталог? */

   if (iPass == 1) /* Вывести имя и атрибуты файла. */

    ProcessItem(&FindData, MAX_OPTIONS, Flags);

   if (FType == TYPE_DIR && iPass == 2 && Recursive) {

    /* Обработать подкаталог. */

    _tprintf(_T ("\n%s\\%s:"), CurrPath, FindData.cFileName);

    /* Подготовка к обходу каталога. */

    SetCurrentDirectory(FindData.cFileName);

    TraverseDirectory(_T("*"), NumFlags, Flags);

    /* Рекурсивный вызов. */

    SetCurrentDirectory(_T(".."));

   }

  } while (FindNextFile(SearchHandle, &FindData));

  FindClose (SearchHandle);

 }

 return TRUE;

}

static BOOL ProcessItem(LPWIN32_FIND_DATA pFileData, DWORD NumFlags, LPBOOL Flags)

/* Выводит список атрибутов файла или каталога. */

{

 const TCHAR FileTypeChar[] = {' ', 'd'};

 DWORD FType = FileType(pFileData);

 BOOL Long = Flags[1];

 SYSTEMTIME LastWrite;

 if (FType != TYPE_FILE && FType != TYPE_DIR) return FALSE;

 _tprintf(_T ("\n"));

 if (Long) { /* Указан ли в командной строке параметр "-1"? */

  _tprintf(_T("%c"), FileTypeChar[FType – 1]);

  _tprintf(_T("%10d"), pFileData->nFileSizeLow); 

  FileTimeToSystemTime(&(pFileData->ftLastWriteTime), &LastWrite);

  _tprintf(_T(" %02d/%02d/%04d %02d:%02d:%02d"), LastWrite.wMonth, LastWrite.wDay, LastWrite.wYear, LastWrite.wHour, LastWrite.wMinute, LastWrite.wSecond);

 }

 _tprintf(_T(" %s"), pFileData->cFileName);

 return TRUE;

}

static DWORD FileType(LPWIN32_FIND_DATA pFileData)

/* Поддерживаемые типы файлов – TYPE_FILE: файл; TYPE_DIR: каталог; TYPE_DOT: каталоги . или .. */

{

 BOOL IsDir;

 DWORD FType;

 FType = TYPE_FILE;

 IsDir = (pFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;

 if (IsDir) if (lstrcmp(pFileData->cFileName, _T(".")) == 0 || lstrcmp(pFileData->cFileName, _T("..")) == 0) FType = TYPE_DOT;

 else FType = TYPE_DIR;

 return FType;

}

Пример: установка меток времени файла

Программа 3.3 реализует UNIX-команду touch, предназначенную для изменения кода защиты файлов и обновления меток времени до текущих значений системного времени. В упражнении 3.11 от вас требуется расширить возможности функции touch таким образом, чтобы новые значения меток времени можно было указывать в параметрах командной строки.

Программа 3.3. touch: установка меток даты и времени файла

/* Глава 3. команда touch. */

/* touch [параметры] [файлы] */

#include "EvryThng.h"

int _tmain(int argc, LPTSTR argv[]) {

 SYSTEMTIME SysTime;

 FILETIME NewFileTime;

 LPFILETIME pAccessTime = NULL, pModifyTime = NULL;

 HANDLE hFile;

 BOOL Flags[MAX_OPTIONS], SetAccessTime, SetModTime, CreateNew;

 DWORD CreateFlag;

 int i, FileIndex;

 FileIndex = Options(argc, argv, _T("amc"), &Flags[0], &Flags[1], &Flags[2], NULL);

 SetAccessTime = !Flags[0];

 SetModTime = !Flags[1];

 CreateNew = !Flags[2];

 CreateFlag = CreateNew ? OPEN_ALWAYS : OPEN_EXISTING;

 for (i = FileIndex; i < argc; i++) {

  hFile = CreateFile(argv[i], GENERIC_READ | GENERIC_WRITE, 0, NULL, CreateFlag, FILE_ATTRIBUTE_NORMAL, NULL);

  GetSystemTime(&SysTime);

  SystemTimeToFileTime(&SysTime, &NewFileTime);

  if (SetAccessTime) pAccessTime = &NewFileTime;

  if (SetModTime) pModifyTime = &NewFileTime;

  SetFileTime(hFile, NULL, pAccessTime, pModifyTime);

  CloseHandle(hFile);

 }

 return 0;

}

Стратегии обработки файлов

Уже на ранних стадиях любого проекта разработки приложения или подготовки его к переносу на другую платформу приходится принимать решение относительно того, должна ли осуществляться обработка файлов с использованием функций библиотеки С или функций Windows. Характер этого решения не относится к категории "или-или", поскольку при соблюдении определенных мер предосторожности смешанное применение функций возможно даже по отношению к одному и тому же файлу.

Библиотека С обладает рядом явных преимуществ, среди которых можно выделить следующие:

• Полученный программный код легко переносится на другие системы.

• Наличие удобных функций для работы с символами и строками, не имеющих прямых аналогов среди функций Windows, упрощает обработку строк.

• Функции библиотеки С обычно проще в использовании по сравнению с функциями Windows.

• Функции, ориентированные на обработку символьных строк и потоков, легко преобразовать к форме, допускающей указание обобщенных символов при их вызове, хотя преимущества переносимости при этом будут утеряны.

• Как показано в главе 7, функции библиотеки С способны работать и в средах с многопоточной поддержкой.