Джонсон Харт - Системное программирование в среде Windows
lpNewFileName — указатель на строку, содержащую имя нового файла или каталога, которые, в случае функции MoveFile, до ее вызова существовать не должны. Новый файл может принадлежать другой файловой системе или находиться на другом диске, но новые каталоги обязательно должны находиться на одном и том же диске. Если значение этого параметра положить равным NULL, то существующий файл будет удален.
dwFlags — позволяет задавать следующие опции:
• MOVEFILE_REPLACE_EXISTING — разрешает замену существующего файла.
• MOVEFILE_WRITETHROUGH — используйте этот флаг, если необходимо, чтобы функция выполнила возврат лишь после того, как файл будет фактически перемещен на диске.
• MOVEFILE_COPY_ALLOWED — если новый файл находится на другом томе, перемещение осуществляется путем последовательного выполнения функций CopyFile и DeleteFile.
• MOVEFILE_DELAY_UNTIL_REBOOT — установка этого флага, использование которого является прерогативой администратора системы и который не может применяться совместно с флагом MOVEFILE_COPY_ALLOWED, приводит к тому, что фактическое перемещение файла будет осуществлено только после перезагрузки системы.
С перемещением (переименованием) файлов связаны некоторые ограничения.
• В Windows 9x функция MoveFileEx не реализована; вместо нее вы должны использовать последовательные вызовы функций CopyFile и DeleteFile. Это делает возможным одновременное существование двух экземпляров файла, что порождает определенные проблемы в случае дисков, близких к заполнению, или файлов большого размера. При этом временные атрибуты файлов изменяются иначе, нежели при истинном перемещении.
• Использование групповых символов в именах файлов или каталогов запрещено. Необходимо указывать фактические имена.
Полные имена файлов в UNIX не включают имен дисков и серверов; корневой системный каталог обозначается обратной косой чертой. В то же время, функции для работы с файлами, входящие в библиотеку Microsoft С, поддерживают имена дисков, как того требуют соглашения Windows относительно именования файлов.
В UNIX отсутствует функция непосредственного копирования файлов. Вместо этого, чтобы выполнить команду cp, вы должны написать небольшую программу или использовать системный вызов system ().
В UNIX эквивалентом функции DeleteFile служит функция unlink, которая, к тому же, может удалять и каталоги.
В библиотеку С входят функции rename и remove, однако функция remove не позволяет присваивать файлу имя уже существующего файла или присваивать каталогу имя существующего непустого каталога. Новое имя может совпадать с именем существующего каталога только в том случае, если этот каталог пустой.
Управление каталогами
Создание и удаление каталогов осуществляется при помощи двух простых функций.
BOOL CreateDirectory(LPCTSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
BOOL RemoveDirectory(LPCTSTR lpPathName)
lpPathName является указателем на завершающуюся нулевым символом строку, которая содержит путь к создаваемому или удаляемому каталогу. Как и в случае других функций, на данном этапе атрибуты защиты файла должны полагаться равными NULL; вопросы безопасности файлов и объектов рассматриваются в главе 15. Удалить можно только пустой каталог.
Как и в UNIX, у каждого процесса имеется текущий, или рабочий, каталог. Кроме того, для каждого диска поддерживается свой рабочий каталог. Программист может как устанавливать рабочий каталог, так и получать информацию о том, какой каталог в данный момент является текущим. Первая функция предназначена для установки каталогов.
BOOL SetCurrentDirectory(LPCTSTR lpPathName)
lpPathName определяет путь к новому текущему каталогу. Это может быть относительный путь или абсолютный полный путь, в начале которого указаны либо буква диска и двоеточие (например, D:), либо имя UNC (например, \ACCTG_SERVERPUBLIC).
Если в качестве пути к каталогу указывается только имя диска (например, А: или С:), то рабочим каталогом становится рабочий каталог данного диска. Например, если рабочие каталоги устанавливались в последовательности:
C:MSDEV
INCLUDE
A:MEMOSTODO
С:
то результирующим рабочим каталогом будет:
C:MSDEVINCLUDE
Следующая функция возвращает абсолютный полный путь к текущему каталогу, помещая его в буфер, предоставляемый программистом:
DWORD GetCurrentDirectory(DWORD cchCurDir, LPTSTR lpCurDir)
Возвращаемое значение: длина строки, содержащей путь доступа к текущему каталогу, или требуемый размер буфера, если буфер не достаточно велик; в случае ошибки — нуль.
cchCurDir — размер буфера, содержащего имя каталога, который определяется количеством символов (а не байт). Размер буфера должен рассчитываться с учетом завершающего нулевого символа строки. lpCurDir является указателем на буфер, предназначенный для получения строки, содержащей путь.
Заметьте, что в случае если размер буфера оказался недостаточным для того, чтобы в нем уместилась вся строка пути, функция возвратит значение, указывающее на требуемый размер буфера. Поэтому при тестировании успешности выполнения функции следует проверять два условия: равно ли возвращаемое значение нулю и не превышает ли оно значение, заданное аргументом cchCurDir.
Подобный метод возврата строк и их длины широко распространен в Windows и требует внимательной обработки результатов. Программа 2.6 иллюстрирует типичный фрагмент кода, реализующего эту логику. Аналогичная логика реализуется и в других примерах. Вместе с тем, указанный метод применяется не всегда. Некоторые функции возвращают булевские значения, а параметр размера в них используется дважды: перед вызовом функции его значение устанавливается равным размеру буфера, а затем изменяется функцией. В качестве одного из многих возможных примеров можно привести функцию LookupAccountName, с которой вы встретитесь в главе 15.
Альтернативный подход, демонстрируемый в программе 15.4 функцией GetFileSecurity, заключается в выделении буферной памяти в промежутке между двумя вызовами функций. Первый вызов обеспечивает получение длины строки, на основании чего и выделяется память, тогда как второй — получение самой строки. Самым простым подходом в данном случае является выделение памяти для строки, насчитывающей МАХ_РАТН символов.
Пример: печать текущего каталога
Программа 2.6 реализует очередную версию команды UNIX pwd. Размер буфера определяется значением параметра МАХ_РАТН, однако проверка ошибок все равно предусмотрена, чтобы проиллюстрировать работу функции GetCurrent-Directory.
Программа 2.6. pwd: печать текущего каталога/* Глава 2. pwd – вывод на печать содержимого рабочего каталога. */
#include "EvryThng.h"
#define DIRNAME_LEN MAX_PATH + 2
int _tmain(int argc, LPTSTR argv[]) {
TCHAR pwdBuffer [DIRNAME_LEN];
DWORD LenCurDir;
LenCurDir = GetCurrentDirectory(DIRNAME_LEN, pwdBuffer);
if (LenCurDir == 0) ReportError(_T("He удается получить путь."), 1, TRUE);
if (LenCurDir > DIRNAME_LEN) ReportError(_T("Слишком длинный путь."), 2, FALSE);
PrintMsg(GetStdHandle(STD_OUTPUT_HANDLE), pwdBuffer);
return 0;
}
Резюме
Наряду с функциями, предназначенными для обработки символов, в Windows поддерживается полный набор функций, обеспечивающих управление файлами и каталогами. Кроме того, вы можете создавать переносимые, обобщенные приложения, которые могут быть рассчитаны на работу как с символами ASCII, так и с символами Unicode.
Функции Windows во многом напоминают их аналоги в UNIX и библиотеке С, хотя различия между ними также очевидны. В приложении Б представлена таблица, в которой сведены функции Windows, UNIX и библиотеки С и показано, в чем они соответствуют друг другу, а в чем заметно отличаются.
В следующих главах
Нашим следующим шагом будет обсуждение в главе 3 прямого доступа к файлам и использования таких атрибутов файлов и каталогов, как размер файла и метки времени. Кроме того, в главе 3 показано, как управлять каталогами, а в завершение главы обсуждается работа с API реестра, аналогичного API управления каталогами.
Дополнительная литература
В книге [22] содержится исчерпывающее обсуждение всего спектра возможных вариантов организации хранения данных в Windows как на непосредственно подключенных, так и на сетевых устройствах. Наряду с внутренними деталями реализации описаны все последние достижения и успехи в данной области, а также прогресс в отношении повышения быстродействия устройств хранения данных.
Книга [10] — это небольшая монография, в которой описаны цели и особенности реализации NTFS. Содержащаяся в ней информация пригодится вам как для этой, так и для следующей глав.