Главная » C++, C++ Builder » Более сложный пример: просмотр атрибутов файлов в CBuilder

0

Простые примеры, которые вы видели в этой главе до сих пор, показывали, как сделать одно или два дела, но не показывали реального законченного примера использования Windows API. В этом примере мы рассмотрим не одну или две функции API, а сразу целую  группу функций, определенную для файловой системы Windows. Пример, который мы собираемся сделать, — простой броузер атрибутов файлов. В нем можно будет выбрать диск, каталог, а затем будет отображена информация об этом диске, каталоге и файлах, находящихся там.

Windows API предоставляет богатый набор функций, которые работают именно с файловой системой. Есть функции, позволяющие найти файлы, подходящие под  заданный  критерий (например, файловую маску), функции для определения объема пространства на диске и функции, возвращающие имена меток диска.

В данном примере мы рассмотрим использование всех этих функции для отображения нужной пользователю информации.

Рис. 9.4. Форма приложения FileAttributeViewer

На рис. 9.4 приведена форма, с которой мы будем работать в этом примере. Вы можете понять, что за информацию  мы будем показывать, исходя из типов управляющих  элементов,  приведенных здесь. Несколько меток статического текста нужны для отображения информации о диске (логическом диске), тогда как сетка строк нужна для отображения информации  об  отдельных файлах в каталоге, выбранном пользователем. Кнопка Просмотр нужна для запуска процесса, а диалог открытия файлов нужен для выбора каталога, с которым следует работать.

Самое первое действие, которое мы должны выполнить, — инициализировать сетку строк, чтобы заголовки столбцов позволяли пользователю понять, что за информацию он видит. Добавьте следующий код в метод FormCreate (обработчик события формы OnCreate):

void __fastcall TForm1::FormCreate(TObject *Sender)

{

StringGrid1->Cells[0][0] = "File Name"; StringGrid1->Cells[1][0] = "Attributes"; StringGrid1->Cells[2][0] = "Size";

StringGrid1->ColWidths[0] = StringGrid1->ClientWidth / 3; StringGrid1->ColWidths[1] = StringGrid1->ClientWidth / 3; StringGrid1->ColWidths[2] = StringGrid1->ClientWidth / 3; StringGrid1->RowCount = 1;

}

Первым делом пользователь будет выбирать каталог из окна диалога открытия файлов (используя кнопку Просмотр). Создайте обработчик нажатия на кнопку Просмотр и добавьте в обработчик код:

void __fastcall TForm1::Button1Click(TObject *Sender)

{

if (OpenDialog1->Execute())

{

// Во-первых, записать диск и каталог

AnsiString strDrive =

ExtractFileDrive (OpenDialog1->FileName) ; AnsiString strDirectory =

ExtractFileDir (OpenDialog1->FileName) ;

// Получить имя метки диска

char szVolName [_MAX_PATH] ; DWORD  dwVolumeSerialNumber=0;

DWORD dwMaxVolumeLength = _MAX_PATH;

DWORD dwFileSystemFlags = 0;

char szFileSystemNameBuffer [_MAX_PATH]; strDrive += "\\";

GetVolumeInformation  (strDrive.c_str(), szVolName, //буфер для метки диска

_MAX_PATH, //длина буфера

// буфер для серийного номера диска

&dwVolumeSerialNumber,

//указатель на максимальную длину имени

//файла в системе

&dwMaxVolumeLength,

//указатель на флаги файловой системы

&dwFileSystemFlags,

//указатель на имя файловой системы

szFileSystemNameBuffer,

_MAX_PATH //длина буфера для имени файловой системы

);

// обработка метки "свободное место на диске" char szBuffer [80] ;

DWORD dwSectorsPerCluster, dwBytesPerSector; DWORD dwFreeClusters, dwClusters;

DWORD dwFreeSpace;  GetDiskFreeSpace(strDrive.c_str(),  &dwSectorsPerCluster,

&dwBytesPerSector, &dwFreeClusters,  &dwClusters); dwFreeSpace =

dwSectorsPerCluster * dwBytesPerSector * dwFreeClusters; sprintf(szBuffer, "%ld", dwFreeSpace) ; DriveFreeSpaceLabel->Caption = szBuffer;

// Поместить информацию в метки

DriveLabel->Caption = strDrive + " [" + szVolName + "]"; DirectoryLabel->Caption = strDirectory;

AnsiString strAll = strDirectory + "\\*.*";

// Теперь получаем все файлы в каталоге, используя

// функцию API FindFile WIN32_FIND_DATA  FindFileData;

HANDLE hFirstFileHandle = FindFirstFile (strAll.c_str(),

&FindFileData) ; int nRow = 1;

while (hFirstFileHandle)

{

// Увеличить количество строк в сетке

StringGrid1->RowCount++;

// Получить размер файла

long lFileSize =

(FindFileData.nFileSizeHigh * MAXDWORD) + FindFileData.nFileSizeLow;

// Получить атрибуты файла

AnsiString strArchive = "";

if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)

strArchive += "A";

if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED)

strArchive += "C";

if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)

strArchive += "D";

if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)

strArchive += "H";

if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY)

strArchive += "R";

if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)

strArchive += "S";

if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY)

strArchive += "T";

// Поместить данные в сетку строк StringGrid1->Cells[0][nRow] = FindFileData.cFileName;

StringGrid1->Cells[1][nRow] = strArchive; sprintf(szBuffer, "%ld", lFileSize) ; StringGrid1->Cells[2][nRow] = szBuffer;

if (FindNextFile (hFirstFileHandle, &FindFileData)

== FALSE)

{

if (GetLastError() == ERROR_NO_MORE_FILES) break;

}

nRow ++;

}

}

}

Это слишком большой кусок кода, чтобы разобрать его сразу весь. Давайте рассматривать его по частям, чтобы попытаться  понять, что  происходит. Сначала пользователь выбирает конкретный файл в каком-нибудь каталоге в окне диалога открытия файла. Когда файл выбран, программа получает букву диска и каталог, в которых лежит файл, используя вспомогательные функции ExtractFileDrive и ExtractFileDir. Эти функции, описанные в заголовочном файле vcl\sysutils.hpp в каталоге с системой CBuilder, возвратят вам части полного  пути файла, соответственно определяющие имя диска и каталог. В случае каталога эта информация включает в себя также и диск (например, D:\dir\), так что мы позже можем использовать ее для поиска файлов в каталоге.

Когда у нас есть имя (буква) диска, на котором находится файл, нашим следующим шагом будет получение метки для этого диска. Имя метки диска — это имя диска, которое появляется в листингах каталогов этого диска. Например, ваш диск C: в Windows Explorer (и других листингах каталогов) выглядит примерно как C: (Windows 95). Имя метки диска в данном случае в скобках, то есть Windows 95. Хотя они и не очень информативны для жестких дисков, как C:, но очень полезны для однозначного определения компакт-диска или другого съемного устройства.

После информации о метке диска наша программа получает  информацию  о  количестве свободного места на диске. Вы, наверное, думаете, что это делается вызовом какой-нибудь одной функции типа GetDriveFreeSpace? Здесь вы ошибаетесь. При запросе о свободном месте на диске функция  API  возвращает  три  разных  значения,  которые  потом  нужно  скомбинировать,  чтобы

получить количество свободного места на диске. Информация, которую мы получаем, включает SectorsPerCluster, то есть количество секторов в одном кластере жесткого диска, затем BytesPerSector, что есть количество байтов в одном секторе диска, и количество свободных кластеров. Между прочим, это очень важные параметры диска.  Некоторые жесткие диски позволяют вам занимать место побайтно, а другие выравнивают все по границе ближайшего кластера. Вот почему размер файла не отражает на самом деле размер дискового пространства, которое этот файл занимает.

Три значения перемножаются, и результат заносится в двойное слово (DWORD) dwFreeSpace. Затем эта информация форматируется и помещается в метку, отображающую свободное пространство на диске.

Вместе со свободным местом на диске в соответствующие поля статического текста (метки) помещаются имя каталога, имя диска и метка диска. Следующий шаг — отображение информации о файлах, находящихся в одном каталоге с выбранным файлом.

Для поиска всех файлов в каталоге используются функции API FindFirstFile и FindNextFile. Эти функции найдут вам файлы, подходящие под заданный критерий, например все файлы (*.*), все исходные файлы (*.cpp) или все библиотечные файлы (*.lib). Кроме того, так как  вы  можете задавать любую маску, вы можете найти все файлы, начинающиеся с «Fred», использовав маску Fred*.* или даже все файлы с Fred внутри их имени, выбрав  *Fred* в качестве  маски.  Маска файлов нечувствительна к регистру символов, так что файлы с большими и маленькими буквами различаться не будут.

Функция API FindFirstFile имеет два параметра: файловую маску и адрес структуры типа WIN32_FIND_DATA. Среди всего прочего, WIN32_FIND_DATA содержит имя файла в элементе структуры cFileName. В случае удачного поиска функция FindFirstFile возвратит ссылку (handle), которую можно потом использовать с функцией API FindNextFile.

Источник: Теллес М. – Borland C++ Builder. Библиотека программиста – 1998

По теме:

  • Комментарии