Назад в раздел
Информация о файлах в Visual Basic и Win32 API
div.main {margin-left: 20pt; margin-right: 20pt}Информация о файлах в
Visual Basic и Win32 API
Введение
Вы,
наверное, обращали внимание на то, как Проводник в Windows работает
с файлами на Вашем компьютере, точнее сколько он собирает информации
о каждом файле? А возможно ли в Visual Basic получить такой объем
данных? Если Вы хорошо знаете Visual Basic, то скажете нет, и я
соглашусь с Вами. Но у программистов на Visual Basic имеется в
распоряжении Win32 API, который, конечно же, нам в этом поможет. Все
примеры кода, которые описаны в этой статье, Вы можете взять здесь.
Что же мы хотим
узнать?
Итак, давайте для начала решим, какие данные о
файлах нам с Вами интересуют. Ну, во-первых, имя файла, во-вторых,
его атрибуты, в-третьих, а что в третьих? Разве средствами Visual
Basic можно выяснить ещё какие-нибудь, нужные для Проводника, данные
о файле?
Атрибуты файла
Задайте себе вопрос,
сколько атрибутов имеет объект файловой системы в Windows? Если Вы
прочитаете справку в Visual Basic, то увидите, что таких атрибутов
шесть: обычный, только для чтения, папка, скрытый, системный,
архивный. Но, если заглянуть в документацию Win32 API или хорошо
подумать, то таких атрибутов оказывается девять! К шести уже
перечисленным, добавляется еще три атрибута, которые, однако, имеют
смысл только в файловой системе NTFS: временный, сжатый и временно
недоступный. Что же делать нормальному программисту, кому верить? Я
считаю, что в данном случае прав Win32 API. Но как себя поведет
Visual Basic если мы будем получать от системы недокументированные с
его точки зрения данные, а никак, он нам этого не запретит, но и не
поможет.
Итак, атрибуты файла можно получить двумя способами.
Первый заключается в вызове стандартной VB функции: GetAttr, которая
вопреки описанию, вернет не шесть, а девять атрибутов объекта
файловой системы. Второй способ заключается в использовании Win32
API и его функций, например FindFirstFile (существует ещё добрый
десяток функций, с помощью которых можно получить ту же информацию),
которая возвратит нам кроме атрибутов ещё ряд полезных данных (но об
этом чуть позже).
О функции GetAttr я рассказывать не буду,
так как она подробно описана в документации по Visual Basic. Скажу
только, что Вы можете с её помощью получать и недокументированные
атрибуты: временный, сжатый и временно недоступный. Для этого нужно
лишь объявить следующие константы:
Public Const
FILE_ATTRIBUTE_ARCHIVE = &H20 Public Const
FILE_ATTRIBUTE_COMPRESSED = &H800 Public Const
FILE_ATTRIBUTE_DIRECTORY = &H10 Public Const
FILE_ATTRIBUTE_HIDDEN = &H2 Public Const
FILE_ATTRIBUTE_NORMAL = &H80 Public Const
FILE_ATTRIBUTE_READONLY = &H1 Public Const
FILE_ATTRIBUTE_SYSTEM = &H4 Public Const
FILE_ATTRIBUTE_TEMPORARY = &H100
Public Const
FILE_ATTRIBUTE_OFFLINE = &H1000
Теперь поговорим о
функции FindFirstFile, она также возвращает информацию о атрибутах
файла, причём в том же виде, что и GetAttr.
'ищем файл и
получаем первую порцию данных о нём hFiles =
FindFirstFile(strFile, fd)
Вызов функции очень простой.
Мы передаем ей имя файла (можно "маску", но об этом в другой раз) и
структуру fd, в которой мы и получим требуемую информацию. Описание
структуры следующее:
Public Type
TFindData dwFileAttributes As Long ftCreationTime As
TFileTime ftLastAccessTime As TFileTime ftLastWriteTime As
TFileTime nFileSizeHigh As Long nFileSizeLow As
Long dwReserved0 As Long dwReserved1 As Long cFileName As
String * MAX_PATH cAlternateFileName As String * 14 End
Type
Как Вы уже, наверное, догадались, первый параметр
этой структуры и есть нужное нам значение для получения атрибутов
объекта файловой системы. Теперь загрузите пример и посмотрите на
атрибуты некоторых файлов. Я, например, не смог на своём жестком
диске найти файл, у которого был бы атрибут временный. Поищите у
себя на диске, если найдете, то напишите, мне очень
интересно!
Когда же ты родился?
Давайте теперь
поговорим о "временах". Файловая система хранит три типа временных
характеристик файла: время создания, время последнего доступа и
время последней модификации (т.е. записи в файл). Но, оказывается,
что и тут не так всё просто. Оказывается, что существуют отличия в
хранении информации между различными файловыми системами. В NTFS все
"времена" сохраняются с точностью до 100 нс, а в FAT время создания
сохраняется с точностью до 100 нс, время последней записи с
точностью до 2 секунд, а время последнего доступа хранится с
точностью до 1 дня. Ну да бог с ними, с этими различиями, Вас,
конечно, интересует вопрос, а как можно получить эту информацию?
Особо догадливые всё поняли ещё в предыдущем параграфе, когда я
описывал Вам структуру TfindData, конечно, там есть специальные поля
для возврата этих дат. Именно поэтому, я и рекомендовал Вам
использовать FindFirstFile, вместо GetAttr. Теперь давайте посмотрим
в каком же формате API вернет нам эти данные? Всё очень запутанно,
эти данные возвращаются в формате Windows и нам их нужно перевести в
родной Visual Basic формат. Для перевода в нужный нам формат мы
пойдём, пожалуй, самым сложным путём, т.е. для этого воспользуемся
Win32 API. Нам потребуется две функции API, немного времени и вагон
терпения. В общем, смотрите пример, там всё это имеется. Но,
существует и ещё один путь перевода дат в нужный нам формат
(основанный на математических вычислениях), но он проходит по узкой
тропинке в тёмном, тёмном лесу, сквозь болото и мрак, и если вдруг
Microsoft в следующей версии Windows изменит внутренний формат этих
данных, то тропинка переместится в какую-нибудь сторону на несколько
метров, и Вы, и Ваш код не смогут там пройти. Мрачно...
Итак,
если Вы хотите, чтобы Ваш код работал с разными файловыми системами
и версиями Windows, то, пожалуйста, обращайте внимание на некоторые
различия в их работе и пользуйтесь общепринятыми функциями для
конвертирования данных в нужный Вам формат..
Как имя твоё,
незнакомец, и кто ты?
Скажите, а Вы задумывались о том,
какое имя файла показывает Проводник? Одни имена файлов показываются
без расширений, другие с расширением, третьи, имеющие несколько
расширений (а кто им это запрещает), показываются совсем по-другому.
Откуда же Проводник черпает эту информацию? Вероятно, запрашивая
данные у функции SHGetFileInfo, которая возвращает данные в
структуре SHFILEINFO.
Public Type SHFILEINFO hIcon As
Long iIcon As Long dwAttributes As Long szDisplayName As
String * MAX_PATH szTypeName As String * 80 End
Type
Итак, как же получить отображаемое имя файла.
Посмотрите, как я вызываю эту функцию. Первый параметр это имя
файла, о котором мы хотим узнать побольше, далее по порядку следует:
атрибуты файла (помните, мы получили их от FindFirstFile?),
структура в которую нам нужно вернуть данные, длина этой структуры и
флаги функции, в зависимости от значений которых, функция возвращает
нам различную информацию (она нам потребуется
дальше):
Call SHGetFileInfo(strFile, fd.dwFileAttributes,
fi, Len(fi), SHGFI_USEFILEATTRIBUTES _ Or SHGFI_DISPLAYNAME Or
SHGFI_TYPENAME)
Я не буду приводить в тексте все флаги
этой функции (смотрите пример), скажу только, что для начала
вызовите её с SHGFI_DISPLAYNAME и SHGFI_TYPENAME и тогда она вернёт
Вам отображаемое имя файла и его тип. Кроме этого, в FAT, существует
ещё оно имя, которое мы с Вами уже получали от FindFirstFile - это
имя в системе MsDOS. Конечно, эта информация Вам вряд ли пригодится,
но раз мы её уже получили, то должны знать.
О отображаемом
имени файла мы уже с Вами говорили, давайте теперь поговорим о типе
файла. Тип файла задается программой, с которой этот файл
ассоциирован. Например, всем известный тип файла "Документ Microsoft
Word" задается программой Microsofr Word, который при установке
делает в реестре специальную запись. Именно по этой записи и
распознаётся тип файла. Описывая файлы, нельзя не упомянуть о
такой их характеристики, как размер. Теоретически размеров файла
может быть два?! Вот, незадача, скажете Вы. Но это так. Существует
реальный теоретический и физический размеры файла. Теоретическим я
называю тот размер, который файл мог бы занимать на диске, а
физический, тот который файл в действительности занимает. Не
вдаваясь в технические подробности, можно коротко это пояснить так.
На диске файлы хранятся в кластерах, которые можно представить в
виде ящиков. Кластеры могут иметь различный размер, который зависит
от типа файловой системы (FAT, NTFS) и размера диска (вот, где
собака то зарыта)! Итак, допустим, что размер кластера на Вашем
диске 4 кБ, тогда файл теоретического размера в 16,5 кБ займёт 4
полных кластера и 5-тый на 500 байт. Вы думаете, что в этот 5-тый
кластер Windows, положит ещё какой-нибудь файл? Нет, она (Windows),
пометит это кластер, как занятый и он останется практически пустой.
Так вот этот файл будет иметь физический размер 20 кБ. Я, в примере,
использую теоретический размер файла, но, в принципе, у системе
можно получить и физический размер.
Как же ты
выглядишь?
Теперь пришло время для получения самой
любопытной, на мой взгляд, информации о файле: его изображение. Дело
в том, что с каждым файлом в системе ассоциировано несколько иконок,
разного размера, а для некоторых типов (например BPM, но не всегда)
можно получить и миниатюрную копию содержимого. Все манипуляции
выполняются функцией SHGetFileInfo, только нужно передавать ей
соответствующие флаги. С помощью этой функции можно получить от
системы маленькие, нормальные и большие иконки, кроме того все они
могут иметь "выделенное" состояние и ещё, в нагрузку, быть
SHGFI_LINKOVERLAY, т.е. иконка, которая отображается на ссылке на
данный файл. Например, для получения маленькой иконки файла нужно
вызывать эту функцию с флагами SHGFI_SMALLICON Or SHGFI_ICON, а для
получения обычной иконки в выделенном состоянии с флагами SHGFI_ICON
Or SHGFI_SELECTED, и т.д. Комбинаций флагов очень много, три типа
иконок, каждая из которых может быть выделенной, для ярлыка (ссылки)
или и то и другое. И ещё, вы получаете от функции не саму иконку, а
её описатель, а вот для того, чтобы его превратить в иконку нужно
изрядно повозиться с OLE. Короче, я всё это представил для Вас в
примере. Там есть специальная функция, которая, с помощью OLE
возвратит Вам по описателю иконки, её изображение. Фу...х, кажется
всё объяснил и рассказал.
В общем, теперь загружайте пример и
изучайте его код. Ну а если кому-то что-то будет не понятно, то
пишите мне, я обязательно
помогу.
Заключение
Конечно, я не описал и
десятой части того, что можно узнать о объекте файловой системы
(файле, каталоге, диске). Например, существует такое понятие, как
тип исполняемого файла, можно посмотреть есть ли у него "внутри"
иконки и т.д. Кроме того, я Вам совсем ничего не рассказал о папках,
а ведь они также, например, имеют свои иконки (видели специальные
папки: "Принтеры", "Корзина"), да что там иконки, они даже
называются по разному! ("Корзина", например называется в
действительности "Recycled"), а как же диски компьютера (CD-ROM,
разные FDD)? Что, голова идет кругом? Ничего, я думаю что тема ,
которую я поднял в этой статье, очень интересная и мы ещё с Вами к
неё вернёмся.. Так, что следите за новостями на моём сайте!
Шатрыкин
Иван
|
|
|
|