Visual Basic, .NET, ASP, VBScript
 

   
 

Родился я 07 ноября 1974 года. Как и все нормальные люди закончил среднюю школу, а потом (уже не как все) пошел учиться в институт. С выбором профессии я явно ошибся ;-) и поступил учиться в сельскохозяйственный институт на технолога сельскохозяйственного производства. Примерно на втором курсе я понял, что жестоко ошибся, но бросать учебу не стал и закончил учебу с дипломом с отличием. Не много думая сразу пошел на второе высшее образование в академию Государственной службы на факультет экономики и, через 3 года, стал дипломированным экономистом со специализацией финансовый менеджмент. Так у меня стало два диплома.
А как же программирование, спросите Вы. Это мое хобби, программирую на VB, пишу сайты на HTML и ASP (посмотрите внимательнее на этот сайт). Могу делать базы данных Access, да и вообще на все руки мастер ;-)).

 
     
   
 

Введение

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

 
     

   
   
     
  VBNet рекомендует