DelphiのTDirectory.GetFilesでファイルの一覧を取得する

以前にC++Builder用に書いた「TDirectory::GetFilesでファイルの一覧を取得する」のDelphi版です。

System.IOUtilsユニットのTDirectory.GetFilesは、指定のディレクトリ内のファイルのリストを返します。
(TDirectory.GetFilesはDelphi 2010/C++Builder 2010で追加された機能です。)

第一引数のPathでファイルを列挙したいディレクトリのパスを指定します。

第二引数のSearchPatternでフィルタリングします。

第三引数のOptionでサブディレクトリも検索するかどうかを指定します。

Pathは必須の引数です。SearchPatternとOptionはオプションです。

uses System.IOUtils, System.Types;

var
  Path: string;
  SearchPattern: string;
  Option: TSearchOption;
  FileNames: TStringDynArray;
  FileName: string;
begin
  // ファイルを列挙したいディレクトリのパス
  Path := Edit1.Text;
  // ファイル名に一致する検索パターン
  SearchPattern := '*.txt';
  // ディレクトリの列挙モード
  Option := TSearchOption.soTopDirectoryOnly; // トップレベル列挙モード
  // Option := TSearchOption.soAllDirectories; // 再帰列挙モード

  //指定のディレクトリ内のファイルのリスト
  FileNames := TDirectory.GetFiles(Path, SearchPattern, Option);
  for FileName in FileNames do
  begin
    ListBox1.Items.Add(FileName);
  end;
end;

フィルタリングをより細かく指定したい時には、TDirectory::TFilterPredicate型を引数に使用します。

var
  Path: string;
  SearchPattern: string;
  Option: TSearchOption;
  FileNames: TStringDynArray;
  FileName: string;
  Filter: TDirectory.TFilterPredicate;
begin
  // ファイルを列挙したいディレクトリのパス
  Path := Edit1.Text;
  // ファイル名に一致する検索パターン
  SearchPattern := '*.txt';
  // ディレクトリの列挙モード
  Option := TSearchOption.soTopDirectoryOnly; // トップレベル列挙モード
  // Option := TSearchOption.soAllDirectories; // 再帰列挙モード

  //望まない結果を除去するために使われるルーチン
  Filter := function(const Path: string; const SearchRec: TSearchRec): Boolean
    begin
      Result := Length(SearchRec.Name) > 5; //5文字以上のファイルのみ
    end;

  //指定のディレクトリ内のファイルのリスト
  FileNames := TDirectory.GetFiles(Path, SearchPattern, Option, Filter);
  for FileName in FileNames do
  begin
    ListBox1.Items.Add(FileName);
  end;

TIdAntiFreezeコンポーネントを配置したDelphiのフォームをC++Builder XE3に追加すると「[ilink32 エラー] Fatal: ファイル ‘DCLINDYCORE.LIB’ を開けません」

概要

TIdAntiFreezeコンポーネントを配置したDelphiのフォームをC++Builder XE3のプロジェクトに追加すると、dclIndyCore.libが開けないというilink32エラーが発生する。

動作環境

C++Builder XE3 Update 2で現象を確認しました。

再現手順

  1. VCLフォームアプリケーションを作成します。

    01

  2. DelphiのVCLフォームを追加します。

    02

    03

  3. DelphiのVCLフォームにTIdAntiFreezeコンポーネントを配置します。

    04

  4. プロジェクトをメイクします。

    05

  5. 「静的ライブラリが見つかりません。dclIndyCore.lib」というダイアログが表示されます。

    dclIndyCore.libというファイルは存在しないため、プログラムを実行することはできません。

    06

    [ilink32 エラー] Fatal: ファイル 'DCLINDYCORE.LIB' を開けません
    

回避策

回避策は不明です。
いい方法がありましたら教えてください。

最後に

たぶんQCに登録されていないと思います。
登録していただけると助かります。<(_ _)>

追記

DEKOさん(@ht_deko)に回避策をおしえていただきました。
また、QCにも登録していただきました。Voteお願いします。

C++Builder XE3でSystem.Generics.Collections.TDictionaryをコンパイルするには

C++Builder XE3で次のコードをコンパイルすると、ilink32 エラーが発生した。

#include <System.Generics.Collections.hpp>

TDictionary__2<int, int>* dic = new TDictionary__2<int, int>(0);

プロジェクトに次のUnit2.pasを追加すると、コンパイルできた。
ユニットを追加するだけで、includeする必要はない。

unit Unit2;

interface

uses System.Generics.Collections;

var dic: TDictionary<Integer, Integer>;

implementation

end.

[Delphi]Windows XPの規則(自然順ソート・natural sort・natural ordering)ででファイル名をソートする

Windows XPのファイル名のソート(ファイル名中の数字を数値と見なすソート)(自然順ソート・natural sort・natural ordering)を実装する方法を紹介します。

Windows XPからファイル名のソート方法が変更されました。
Windows 2000まではアルファベット順のソートでしたが、Windows XPからはファイル名に含まれる数字を数値をに見なしてソートしています。
※参考:名前に数字が含まれるファイルやフォルダの並べ替え順序が Windows XP と Windows 2000 で異なる

Windows XPのソート

Ie4_01
Ie4_128
Ie5
Ie6
Ie401sp2
Ie501sp2

Windows 2000のソート

Ie4_01
Ie4_128
Ie401sp2
Ie5
Ie501sp2
Ie6

StrCmpLogicalW関数を使った方法

自作のソフトウェアでWindows XPのソートを実装する場合は、shlwapi.dllのStrCmpLogicalW関数を使用します。

function StrCmpLogicalW(psz1, psz2: PWideChar): Integer; stdcall; external 'shlwapi.dll';

次のサンプルプログラムではTStringListの文字列を2種類の方法でソートします。

/// <summary>
///   TStringList.CustomSortでWindows XPのソートをするための比較関数
/// </summary>
function CompareLogical(List: TStringList; Index1, Index2: Integer): Integer;
begin
  Result := StrCmpLogicalW(PWideChar(List[Index1]), PWideChar(List[Index2]));
end;

var
  SL: TStringList;
  S: string;
begin
  // テストデータ
  SL := TStringList.Create;
  SL.Add('Ie5');
  SL.Add('Ie6');
  SL.Add('Ie401sp2');
  SL.Add('Ie4_128');
  SL.Add('Ie501sp2');
  SL.Add('Ie4_01');

  // アルファベット順のソート。Windows2000と同じ結果
  SL.Sort;
  for S in SL do
    Writeln(S);

  // WindowsXP以降の規則でソート
  SL.CustomSort(CompareLogical);
  for S in SL do
    Writeln(S);

StrCmpLogicalW関数を使わない方法

StrCmpLogicalW関数はWindowsでしか使えません。
他のOSで使えるようにDelphiでコードを書きました。

次のページを参考にしました。
DaveKoelle.com | The Alphanum Algorithm

/// <summary>
/// 自然順ソードの比較
/// </summary>
function NaturalSortCompare(const S1, S2: string): Integer;
const
  RE_CHUNK: string = '([\D]+|[\d]+)';
  RE_LETTERS: string = '\D+';
  RE_NUMBERS: string = '\d+';
var
  L, R: string;
  LChunk, RChunk: string;
  ReChunk, ReLetter, ReNumber: TRegEx;

  /// <summary>
  /// 文字列の先頭から、連続する数字または文字列を取得する
  /// </summary>
  function GetChunk(var S: string): string;
  var
    Match: TMatch;
  begin
    Match := ReChunk.Match(S);
    if Match.Success then
    begin
      Result := Match.Groups[0].Value;
      S := S.Substring(Result.Length);
    end
    else
    begin
      Result := '';
    end;
  end;

/// <summary>
/// 文字列を数値として比較して、S1が小さいときは-1、S2が小さいときは1、等しいときは0を返す
/// </summary>
  function CompareNum(const S1, S2: string): Integer;
  var
    Num1, Num2: Integer;
  begin
    Num1 := StrToInt(S1);
    Num2 := StrToInt(S2);
    if Num1 < Num2 then
      Result := -1
    else if Num1 > Num2 then
      Result := 1
    else
      Result := 0;
  end;

begin
  Result := 0;
  L := S1;
  R := S2;
  ReChunk := TRegEx.Create(RE_CHUNK);
  ReLetter := TRegEx.Create(RE_LETTERS);
  ReNumber := TRegEx.Create(RE_NUMBERS);

  while Result = 0 do
  begin
    if L.IsEmpty and R.IsEmpty then
      Exit(CompareStr(S1, S2));

    LChunk := GetChunk(L);
    RChunk := GetChunk(R);

    if ReLetter.Match(LChunk).Success and ReLetter.Match(RChunk).Success then
    begin
      Result := CompareStr(LChunk, RChunk);
    end
    else
    begin
      if ReNumber.Match(LChunk).Success and ReNumber.Match(RChunk).Success then
      begin
        Result := CompareNum(LChunk, RChunk);
      end
      else
      begin
        Result := CompareStr(LChunk, RChunk);
        if Result = 0 then
          Result := 1;
      end;
    end;
  end;
end;

function NaturalSort(List: TStringList; Index1, Index2: Integer): Integer;
begin
  Result := NaturalSortCompare(List[Index1], List[Index2]);
end;

var
  SL: TStringList;
  S: string;
begin
  // テストデータ
  SL := TStringList.Create;
  SL.Add('Ie5');
  SL.Add('Ie6');
  SL.Add('Ie401sp2');
  SL.Add('Ie4_128');
  SL.Add('Ie501sp2');
  SL.Add('Ie4_01');

  // WindowsXP以降の規則でソート
  SL.CustomSort(NaturalSort);
  for S in SL do
    Writeln(S);

  SL.Free;
end.

更新履歴

  • 2013/11/04 StrCmpLogicalW関数を使わない方法を追加しました。