Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Урок 12 - Cоздание списка файлов

Ведущий раздела KOL и MCK: Анатолий aka XVeL
Автор: Борис Моренко
WEB-сайт: http://kol.mastak.ru

Полную версию библиотеки KOL и MCK можно скачать здесь.

Не так уж и часто, но бывает надо в программе получить список файлов или поддиректорий в каталоге. Для тех, кто использует KOL и MCK открываются аж 3 способа решения этой проблемы. Правда нормальный, по моему мнению, все-таки только один :) Рассмотрим все.

1-й способ. " Традиционный ."

Традиционно пользуются 3-мя API функциями: FindFirstFile (ищет первый файл из списка файлов), FindNextFile (ищет следующий файл) , FindClose (прекращение поиска). Обычно первые 2-е функции заменются их VCL-суррогатами FindFirst, FindNext. Для нас, они не совсем приемлемы, так как для того чтобы воспользоваться этими функциями, надо подключить библиотеку Sysutils. А это как известно добавляет лишний жирок в наши атлетически сложенные программы :-). Пример на чистом API с примесью KOL.

program Primer12;

uses
  Windows,
  Messages,
  Kol;

  {$R *.RES}
var
  Form: Pcontrol;
  // ----- элементы интерфейса ----- 
  List: PControl;
  // -----------------------------
  FindHandle : THandle;
  FindData : TWin32FindData;
  b: boolean;
  s: string;
begin
  Applet := NewApplet( 'Список файлов' );
  form:=NewForm(Applet, 'Список файлов' ).SetSize(300, 400);
  form.CenterOnParent;
  List := NewListBox(form, []).SetAlign(caClient);

  // устанавливаем атрибуты файла 
  FindData.dwFileAttributes := FILE_ATTRIBUTE_NORMAL;
  // ищем первый файл в каталоге C:\
  FindHandle := FindFirstFile('C:\*.*', FindData);
  // если все Ok, тогда продолжаем 
  if FindHandle <> INVALID_HANDLE_VALUE then
  begin
     b := true;
     while b do
     begin
       s := FindData.cFileName;
       // всякие точки и двоеточия нам не нужны 
       if (s<>'..') and (s<>'.') then
         List.Add(s);
       b := FindNextFile(FindHandle, FindData);
     end;
  end;
  FindClose(FindHandle);

  run(Applet);
end.

Пояснения на счет атрибутов для искомых файлов:

  • FILE_ATTRIBUTE_ARCHIVE - архивный файл.
  • FILE_ATTRIBUTE_COMPRESSED - сжатый файл или папка.
  • FILE_ATTRIBUTE_HIDDEN - скрытый файл.
  • FILE_ATTRIBUTE_NORMAL - обычный файл.
  • FILE_ATTRIBUTE_OFFLINE - данные файла недоступны. Указывает, что данные файлы были физически перемещены.
  • FILE_ATTRIBUTE_READONLY - файл только для чтения.
  • FILE_ATTRIBUTE_SYSTEM - системный файл.
  • FILE_ATTRIBUTE_TEMPORARY - временный файл.
  • FILE_ATTRIBUTE_DIRECTORY - директория

2-й способ. "В лоб."

Несмотря на простоту представленного кода эту операцию можно сделать еще проще т.к. ListBox сам может показать файлы в определенной директории. Для этого надо обратится к свойству AddDirList. Пример еще меньше.

program Primer12_2; 
 
uses 
  Windows, 
  Messages, 
  Kol; 
 
{$R *.RES} 
var 
  Form: Pcontrol; 
  // ----- элементы интерфейса ----- 
  List: PControl; 
  // ------------------------------ 
begin 
  Applet := NewApplet('Список файлов'); 
  form := NewForm(Applet, 'Список файлов').SetSize(300, 400); 
  form.CenterOnParent; 
  List := NewListbox(form, []).SetAlign(caClient); 
  List.AddDirList('C:\*.*', FILE_ATTRIBUTE_NORMAL); 
  run(Applet); 
end. 

Это конечно интересный способ получать список файлов, но не функциональный :) Не создавать ведь на окне каждый раз ListBox или СomboBox (он тоже имеет это же свойство), чтобы получить список файлов. Да и почему-то выводимый список файлов в виде " коротких имен " (т.е. как будто в DOS). Скорее всего Владимир Кладов добавил это свойство как интересную фичу и не более.

3-й способ. " Как положено "

Ну и самое интересное :) В KOL есть объект предназначенный для создания списка фалов. Это PDirList. Вот его конструктор:

function NewDirList( const DirPath, Filter: String; Attr: DWORD ): PDirList;

DirPath - сканируемая директория
Filter - фильтр для файлов или каталогов
Attr - атрибуты

Список методов и свойств для работы с этим обьектом:

Метод
Описание
procedure Clear; Очищает текущий список с файлами.
procedure ScanDirectory( const DirPath, Filter: String; Attr: DWord ); Сканирует директорию DirPath. Все передаваемые значения идентичны конструктору.
procedure Sort( Rules: array of TSortDirRules );

Сортировка списка файлов. Rules (условие сортировки) может быть следующим :

  • sdrNone - обойдемся без сортировки
  • sdrFoldersFirst - сначала идет каталог, а только затем файл.
  • sdrCaseSensitive
  • sdrByName - по имени
  • sdrByExt - по расширению
  • sdrBySize - по размеру
  • sdrBySizeDescending
  • drByDateCreate - по дате создания
  • sdrByDateChanged - по дате изменения
  • sdrByDateAccessed -по дате доступа
Свойство
Описание
property Items[ Idx: Integer ]: PWin32FindData Получить доступ к структуре PWin32FindData для файла идущего под номером Idx. Подробности об PWin32FindData смотрите в Win32.hlp и в примере " стандартного " создания списка фалов
property IsDirectory[ Idx: Integer ]: Boolean; Возвращает true если запись под номером Idx в списке не является файлом.
property Count: Integer;

Возвращает количество пунктов в списке

property Names[ Idx: Integer ]: string; Возвращает полное имя файла (или каталога) находящимся в списке под номером Idx.
property Path: string; Путь текущей просканированной директории.

Пример. Наверху в окне находится список дисков. Ниже находится список файлов и подкаталогов, находящихся в центральных каталогах этих дисков.

program Primer12_3;

uses
  windows,
  messages,
  kol;

{$R *.RES}
var
  form: Pcontrol;
 // ----- элементы интерфейса -----
  ListFile, ListDrv: PControl;
 // ------------------------------
  FileL: pDirList;

  i, j: integer;

  DriveBits: set of 0..25;
  DriveNum: integer;
  DriveChar: char;

///////////////////////////////////////////////////////////////////////////

procedure SelDrv(Dummy: Pointer; Sender: PControl);
var
  s: string;
begin
  s := ListDrv.Text;

  if FileL = nil then
    FileL := NewDirList(s, '*.*', FILE_ATTRIBUTE_NORMAL)
  else
  begin
    FileL.Clear;
    FileL.ScanDirectory(s, '*.*', FILE_ATTRIBUTE_NORMAL);
  end;
  FileL.Sort([sdrByName]);

  ListFile.Clear;
  if FileL.Count > 0 then
    for i := 0 to FileL.Count - 1 do
      ListFile.add(FileL.Names[i]);
end;
///////////////////////////////////////////////////////////////////////////
begin
  Applet := NewApplet('Список файлов');
  form := NewForm(Applet, 'Список файлов').SetSize(250, 300);
  form.CenterOnParent;
  Form.Font.FontName := 'MS Sans Serif';
  Form.Font.FontHeight := 9;

 //----------- "рисуем" интерфейс -----------------------
  ListDrv := NewComboBox(form, []).SetAlign(caTop);
  ListFile := NewListbox(form, []).SetAlign(caClient);
 //------------------------------------------------------

  Integer(DriveBits) := GetLogicalDrives; // получаем номера дисков
  i := 0;
  j := 0;

 // узнаем список дисков
  for DriveNum := 0 to 25 do
    if DriveNum in DriveBits then
    begin
      DriveChar := Char(DriveNum + Ord('a'));
      DriveChar := UpCase(DriveChar);
      ListDrv.Add(DriveChar + ':\');
      if DriveChar = 'C' then j := ListDrv.Count - 1; // узнаем каким в очереди идет диск С:\
    end;

  ListDrv.CurIndex := j;
  ListDrv.OnChange := TOnEvent(MakeMethod(nil, @SelDrv));
  SelDrv(nil, nil); // показываем файлы на текущем диске
  run(Applet);
end.

Размер кода 1,8 Кб. Размер программы 34,5 Кб (без сжатия и замены модулей). На экране увидите Вы примерно следующее:

Проект Delphi World © Выпуск 2002 - 2004
Автор проекта: ___Nikolay