Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Сортировка файлов или папок


Автор: Keeper89 29.10.2009, 00:04
Доброго времени суток!

Есть функция, где происходит поиск файлов через TSearchRec. Далее в этой же функции планируется сортировка различного типа (по имени, дате создания, размеру и т.д. + убыв./возр.) и на выходе получается соотв. отсортированный список файлов в формате TStringList.

Подскажите, каким образом лучше осуществить сортировку и вообще организовать функцию?


Автор: Beltar 29.10.2009, 00:20
А просто сгрести все нужное содержимое к какую-то таблицу (например контейнер на основе TList, у него и сортировка есть) к которой потом применять сортировку с нужной функцией сравнения? Мне кажется это оптимальный способ т. к. сортировка выполниться всего один раз, а иначе придется каждый раз считав файл искать двоичным поиском его место в таблице.

Или я чего-то не понял?

Автор: Keeper89 29.10.2009, 00:56
Beltar, небольшой пример можно?

Автор: Qu1nt 29.10.2009, 01:26
Код

uses
  Math;

function CompareDates(List: TStringList; Index1, Index2: Integer): Integer;
begin
  Result := CompareValue(StrToDate(List[Index1]), StrToDate(List[Index2]));
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  List: TStringList;
begin
  List := TStringList.Create;
  try
    List.Add('21.12.2012');
    List.Add('29.10.2009');
    List.Add('05.12.2010');
    List.CustomSort(CompareDates);
    ListBox1.Items.Assign(List);
  finally
    List.Free;
  end;
end;

Автор: Keeper89 29.10.2009, 02:19
Qu1nt, 
А где тогда будут храниться остальные данные (имена, даты создания и т.п.)?

Автор: Qu1nt 29.10.2009, 10:59
Ты данные куда выводишь? В TListView? Тогда можно сделать сортировку по нажатию на колонку.

Автор: Keeper89 29.10.2009, 11:23
Я, как говорил в 1 посте, вывожу только имена после сделанной сортировки.

Автор: Qu1nt 29.10.2009, 15:22
Набросал, вот:
Код

{ by Qu1nt }
program Project1;

{$APPTYPE CONSOLE}

uses
  Windows, SysUtils, Classes, Contnrs, Math;

type
  TFile = class
    constructor Create(const Name: AnsiString; Size: Int64; Time: Integer);
  private
    Name: AnsiString;
    Size: Int64;
    Time: Integer;
  end;

  TFiles = class(TObjectList)
    constructor Create(const Path, Mask: AnsiString);
  public
    type
      TOrder = (ORDER_ASC, ORDER_DESC);
      TSort  = (SORT_NAME, SORT_SIZE, SORT_DATE);
    procedure Print(const SortFlags: array of TSort;
      OrderType: TOrder = ORDER_ASC; List: TStrings = nil);
  private
    class var
      SortFlags : array of TSort;
      Order : TOrder;
  end;

function EpicSort(Item1, Item2: Pointer): Integer;
var
  SortFlag: TFiles.TSort;
begin
  Result := 0;
  for SortFlag in TFiles.SortFlags do
  begin
    case SortFlag of
      SORT_NAME : Result := AnsiCompareStr(TFile(Item1).Name, TFile(Item2).Name);
      SORT_SIZE : Result := CompareValue(TFile(Item1).Size, TFile(Item2).Size);
      SORT_DATE : Result := CompareValue(TFile(Item1).Time, TFile(Item2).Time);
    end;
    // по убыванию? инвертируем результат
    if TFiles.Order = ORDER_DESC then
      Result := - Result;
    // если сравниваемые данные не равны
    if Result <> 0 then
      Exit;
  end;
end;

{ TFile }
constructor TFile.Create;
begin
  Self.Name := Name;
  Self.Size := Size;
  Self.Time := Time;
end;

{ TFiles }
constructor TFiles.Create;
var
  SearchRec: TSearchRec;
begin
  inherited Create;
  // ищем файлы по заданной маске, директории игнорируются
  if FindFirst(IncludeTrailingPathDelimiter(Path) + Mask,
    faAnyFile - faDirectory, SearchRec) = 0 then
  repeat
    // добавляем в список
    with SearchRec do
      Add(TFile.Create(Name, Size, Time));
  until FindNext(SearchRec) <> 0;
  FindClose(SearchRec);
end;

procedure TFiles.Print;

  function PrintLn(const Line: AnsiString): AnsiString;
  begin
    if Line <> '' then
    begin
      SetLength(Result, Length(Line));
      // корректный вывод русских букавок = )
      CharToOem(PAnsiChar(Line), PAnsiChar(Result));
    end;
    WriteLn(Result);
  end;

var
  Item: Pointer;
begin
  // если не указали ниодного типа сортировки - сортировать не будем
  SetLength(Self.SortFlags, Length(SortFlags));
  if Length(Self.SortFlags) > 0 then
  begin
    System.Move(SortFlags[0], Self.SortFlags[0], Length(SortFlags) * SizeOf(TSort));
    Self.Order := OrderType;
    // наша эпическая сортировка
    Sort(EpicSort);
  end;
  // если указан список - пишем в него
  // очистка списка, Begin-EndUpdate на Ваших плечах :)
  for Item in Self do
    with TFile(Item) do
      if Assigned(List) then
        List.Append(Name)
      else
        PrintLn(Name);
end;

begin
  // получаем список файлов только один раз - в конструкторе
  with TFiles.Create('c:\', '*.*') do
    try
      // указываем тип, порядок сортировки и выходной список
      // сортировки: SORT_NAME, SORT_SIZE, SORT_DATE - по имени, размеру, дате
      // порядок: ORDER_ASC, ORDER_DESC - по возрастанию, убыванию
      //
      // можно сортировать сразу по нескольким параметрам
      // например, нижеприведенный пример будет сперва сравнивать размеры
      // двух файлов. Если они одинаковы - дополнительно сравнит их имена
      Print([SORT_SIZE, SORT_NAME], ORDER_DESC);
      // Print([SORT_DATE, SORT_SIZE, SORT_NAME]); ORDER_ASC - по-умолчанию
      // Print([]); - без сортировки
      // Print([SORT_NAME], ORDER_ASC, List); - запись в список
    finally
      // освобождаем память
      Free;
    end;
  ReadLn;
end.

Автор: Beltar 29.10.2009, 16:57
Цитата

 небольшой пример можно?


Примерно за 50 минут, включая время на поиск мегадурацкой ошибки мой мозг родил вот это. Только компонент из архива сначала установи.

Автор: Keeper89 29.10.2009, 22:12
Qu1nt, 
Beltar, 
спасибо посмотрю.

Qu1nt, что означает процедура PrintLn, которая "должна работать"? smile

Автор: Qu1nt 29.10.2009, 22:13
Корректный вывод русских букавок в консоль = )

Автор: Keeper89 29.10.2009, 22:17
Я так и подумал, спс, пример отличный, пока поразбираюсь в нем.

Автор: Qu1nt 30.10.2009, 00:19
Оптимизировал пример, обновил пост.

Автор: Qu1nt 30.10.2009, 14:48
Добавил возможность сортировки по нескольким параметрам. 

Автор: Keeper89 31.10.2009, 10:45
А в чем заключалась оптимизация?

Автор: Qu1nt 31.10.2009, 10:54
Избавился от лишней переменной в конструкторе, добавил модификатор const к входным строковым параметрам.

Автор: Keeper89 1.11.2009, 00:16
Я создал 2 класс - точную копию TFiles для поиска только ярлыков. Можно ли как-то изменить процедуру EpicSort, чтобы она воспринимала не только TFiles.SortType, но TShortCuts.SortType?
Может вынести Тип Сортировки из класса или нет?

Автор: Qu1nt 1.11.2009, 12:10
Сделай их глобальными переменными и все = )
Код

class var
  SortFlags : array of TSort;
  Order : TOrder;

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)