Вы, наверное, обращали внимание на то, как
Проводник в 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)? Что, голова идет кругом? Ничего, я думаю что тема ,
которую я поднял в этой статье, очень интересная и мы ещё с Вами к неё
вернёмся.. Так, что следите за новостями на моём сайте!