[delphi-users:2952] TDirectory.GetFilesで隠しフォルダ配下のファイルは列挙したくない

293 views
Skip to first unread message

Delフサギコ

unread,
Jan 10, 2013, 10:15:14 AM1/10/13
to DelphiML
こんにちは。
TDirectory.GetFilesを使用してファイルをリストアップしてみたのですが、隠しフォルダ配下のファイルまで入ってきてしまっていたので
対応策を考えてみたのですが、
なんだか上手なやり方を思い浮かびませんでした。

隠しフォルダに格納されているファイルをリストアップしないやり方は
どのようにやるかご存知の方おられましたら教えてください。

こんな簡単な事、簡単にできそうなのに
なんだか簡単にできそうにないジレンマを感じます。


TDirectory.GetFilesは無名メソッドで条件を指定したりもできることは知っています。
しかし、ファイルには隠しファイル属性はついていないが
上位フォルダのどこかに隠し属性が付いている場合には
そのファイルをリストアップしたくない、ということです。

列挙されたファイルに対して全ての親をたどって
隠し属性の有無を調べるのも、動作が遅そうですし
動的配列の削除コードも遅いものになりそうなので
なんだかすっきりしないのです。

(※動的配列の項目削除で高速なやり方をご存じの方、いたらそちらも教えてください)

よろしくおねがいします。

--
--
Delフサギコ  ミ・д・彡 <delfu...@gmail.com>

DEKO

unread,
Jan 10, 2013, 11:09:55 PM1/10/13
to delphi...@freeml.com
こんにちは。

> こんな簡単な事、簡単にできそうなのに
> なんだか簡単にできそうにないジレンマを感じます。
簡単かそうでないかは個人差があるかと思いますが、
とりあえず以下のようなコードでお望みの事ができるような気がします。

|uses
| ..., System.Types, System.IOUtils;
|
|procedure TForm1.Button1Click(Sender: TObject);
|var
| SA: TStringDynArray;
| i: Integer;
|begin
| SA := TDirectory.GetFiles('C:\TEST', '*.*', TSearchOption.soAllDirectories,
| function (const Path: string; const SearchRec: TSearchRec): Boolean
| begin
| result := (not (TFileAttribute.faHidden in TDirectory.GetAttributes(Path))) and
| ((faHidden and SearchRec.Attr) = 0);
| end);
| for i:=Low(SA) to High(SA) do
| Memo1.Lines.Add(SA[i]);
|end;

# System.IOUtils のクラスについては、
# 山本隆さんのブログがとても参考になります。
# http://www.gesource.jp/weblog/

--
by DEKO
-----------------------------
http://ht-deko.minim.ne.jp/
de...@ht-deko.minim.ne.jp
-----------------------------


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
いつでもどこでもメールチェック!freemlのスマートフォンアプリ
http://ad.freeml.com/cgi-bin/sa.cgi?id=jwpen
------------------------------------------------------[freeml byGMO]--

Delフサギコ

unread,
Jan 11, 2013, 5:49:52 AM1/11/13
to "delphi-users@freeml.com"
いつもお世話になります。
下記コードだと、二階層上のフォルダが
隠し属性な場合、列挙されてしまう気がするのです。

動作確認できてないので、かえってからしてみます。
MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
かわいいベジモンがたくさん!自分だけの農場を作ろう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=jwvlI
------------------------------------------------------[freeml byGMO]--

DEKO

unread,
Jan 11, 2013, 2:10:28 PM1/11/13
to delphi...@freeml.com
こんにちは。

> いつもお世話になります。
> 下記コードだと、二階層上のフォルダが 隠し属性な場合、列挙されてしまう気がするのです。

確かにそうですね。
そうなると理屈上 "検索は (ドライブ) ルートフォルダから行わなくてはならない" という事になってしま
いますので、

function EnumFiles_WithOutHidden(const Path: string; SearchPattern: string): TStringDynArray;
var
FA: TFileAttributes;
dPath, dCPath, PathRoot: string;
Hidden_Flg: Boolean;
HiddenList, PathList: TStringDynArray;
begin
// 配列を初期化
SetLength(result, 0);
// 絶対パスを生成
if TPath.IsRelativePath(Path) then
dPath := TPath.GetFullPath(Path)
else
dPath := ExcludeTrailingPathDelimiter(Path);
// 上の階層のフォルダを検索
Hidden_Flg := False;
PathRoot := ExcludeTrailingPathDelimiter(TPath.GetPathRoot(dPath));
dCPath := dPath;
repeat
FA := TDirectory.GetAttributes(dCPath);
if (TFileAttribute.faHidden in FA) then
begin
Hidden_Flg:= True;
Break;
end;
dCPath := TPath.GetDirectoryName(dCPath + '.a');
until ((dCPath) <> PathRoot);
// 指定フォルダが隠し属性フォルダ内だったら抜ける
if Hidden_Flg then
Exit;
// 指定パス以下の隠しフォルダを列挙
HiddenList := TDirectory.GetDirectories(dPath, '*.*', TSearchOption.soAllDirectories,
function (const Path: string; const SearchRec: TSearchRec): Boolean
begin
result := ((faHidden and SearchRec.Attr) > 0);
end);
// 隠しフォルダ内のフォルダは隠しフォルダとみなす
PathList := TDirectory.GetDirectories(dPath, '*.*', TSearchOption.soAllDirectories,
function (const Path: string; const SearchRec: TSearchRec): Boolean
var
l: Integer;
begin
result := ((faHidden and SearchRec.Attr) > 0);
if result then
Exit;
for l:=Low(HiddenList) to High(HiddenList) do
begin
if Pos(HiddenList[l], Path) = 1 then
begin
result := True;
break;
end;
end;
end);
// 指定パス以下のファイルを列挙
result := TDirectory.GetFiles(dPath, SearchPattern, TSearchOption.soAllDirectories,
function (const Path: string; const SearchRec: TSearchRec): Boolean
begin
result := ((faHidden and SearchRec.Attr) = 0) and
(IndexText(Path, PathList) = -1);
end);
end;

こんな事になるかと思います。使い方は次の通りです。

procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
Files: TStringDynArray;
begin
Files := EnumFiles_WithOutHidden('C:\TEST', '*.*');
for i:=Low(Files) to High(Files) do
Memo1.Lines.Add(Files[i]);
end;

あまり検索効率がいいとは思えませんが "TDirectory.GetFiles 縛り" という事で参考までに。
(FindFirst / FindNext / FindClose の再帰で書いたほうがスッキリすると思います)

--
by DEKO
-----------------------------
http://ht-deko.minim.ne.jp/
de...@ht-deko.minim.ne.jp
-----------------------------


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
アイテムたくさん☆freemlのプロフィール画像をアバターに♪
http://ad.freeml.com/cgi-bin/sa.cgi?id=jwzMU
------------------------------------------------------[freeml byGMO]--

DEKO

unread,
Jan 11, 2013, 3:29:49 PM1/11/13
to delphi...@freeml.com
スミマセン、コードがちょっと変です。

誤: until ((dCPath) <> PathRoot);
正: until (dCPath = PathRoot);

--
by DEKO
-----------------------------
http://ht-deko.minim.ne.jp/
de...@ht-deko.minim.ne.jp
-----------------------------


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
ニコラスケイジ主演映画「ゴーストライダー」試写会にご招待
http://ad.freeml.com/cgi-bin/sa.cgi?id=jwzZp
------------------------------------------------------[freeml byGMO]--

Delフサギコ

unread,
Jan 11, 2013, 10:51:25 PM1/11/13
to delphi...@freeml.com
お世話になります。

なるほどなるほど!
隠し属性のフォルダを列挙して
それにあてはまるかどうかでファイルを判定ですか。

> そうなると理屈上 "検索は (ドライブ) ルートフォルダから行わなくてはならない" という事になってしま
> いますので、

うーん、確かにそういうわれるとそうか。
渡されたパスの上位パスが全て隠し属性じゃないことも判定しておかないと
いけない、って話になるわけですね。
するどいです。

> あまり検索効率がいいとは思えませんが "TDirectory.GetFiles 縛り" という事で参考までに。
> (FindFirst / FindNext / FindClose の再帰で書いたほうがスッキリすると思います)

そうですよね。


以前、GetFilesを自前実装したことがあってブログに書いていたのですが

DelFusa ポエム Blog 容量デカイの気に食わず TDirectory.GetFilesなどを自前実装した
http://delfusa.blog65.fc2.com/blog-entry-282.html

Filter関数を無名関数で指定できるようにしたのですが、
再帰呼び出しするかどうかも、無名関数で指定できるように機能追加したほうが
より汎用的な部品になりそうだと思いました。

汎用部品を作るって難しいもんですね。


非常に丁寧なコードありがとうございます。
勉強になります。

--
Delフサギコ ミ・д・彡 <delfu...@gmail.com>




> 送信者 DEKO <delphi...@freeml.com>
> 宛先 delphi...@freeml.com
> 日時 2013/01/12(土) 4:10:29
> 件名 [delphi-users:2955] Re: TDirectory.GetFilesで隠しフォルダ配下のファイルは列挙したくない
> ----
使い方はいろいろ♪一部のメンバーだけにMLメールを送ろう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=jw3Mv
------------------------------------------------------[freeml byGMO]--

DEKO

unread,
Jan 11, 2013, 11:01:59 PM1/11/13
to delphi...@freeml.com
こんにちは。
比較的読みやすいコードを自サイトの方に上げておきました。

[隠し属性のフォルダとファイルを除外してファイルをリストアップ ]
http://ht-deko.minim.ne.jp/ft1301.html#130112_01

# コードの不備を修正済です。
# FindFirst / FindNext / FindClose での実装コードもあります。

--
by DEKO
-----------------------------
http://ht-deko.minim.ne.jp/
de...@ht-deko.minim.ne.jp
-----------------------------


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
メンバーで使える掲示板を活用しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=jw3Wr
------------------------------------------------------[freeml byGMO]--

Delフサギコ

unread,
Jan 12, 2013, 3:19:50 AM1/12/13
to DelphiML
するどく、かつ、すばやいアップありがとうございます。

2013年1月12日 13:02 DEKO <delphi...@freeml.com>:

比較的読みやすいコードを自サイトの方に上げておきました。

[隠し属性のフォルダとファイルを除外してファイルをリストアップ ]
http://ht-deko.minim.ne.jp/ft1301.html#130112_01

# コードの不備を修正済です。
# FindFirst / FindNext / FindClose での実装コードもあります。

ホームページの方に書かれていたのですが
偽DelFusaはどうやら私の
もしくは人類の負の部分を練り固めて生まれた存在みたいですから
相手しないでいいと思いますよ。
他の人のつぶやきのネガティブな側面だけに反応するらしいので
誰かのために何かするなんて事はないわけですから...
人の揚げ足とるだけしか能がないのでしょう。

あと、
>Delphi-freeml に投稿するとインデントが失われる
やっぱりですか。
なんか不思議に思っていて
自分のアカウントがGMailだからだと思ってしまいました。
インデントを全角スペースに変換してから投稿するようにしたいですね。

ほんといつもありがとうございます。

 インデントテスト
  インデントテスト
   インデントテスト
    インデントテスト
Reply all
Reply to author
Forward
0 new messages