UnifinityでGUI付きバッチを作る(フォルダーツリー作成編)

テックポエム

かくして依頼は舞い降りた

ベンチャーだからなのか、役職なのか、ずっと会社にいるからなのかは定かではありませんが、私の業務の中には「なんでも屋さん」というものがあります。
先日も、人事総務の方からこんな依頼が届きました。

「社内NASにあるファイルを整理したいので、ファイル一覧をExcelで把握したい」
「フォルダー階層ごとにインデントがついて見やすいと嬉しい」
「フォルダーとファイルを区別するため、フォルダーにはマークを付けたい」

聞いてみると、NASにいろいろなファイルが散在しているため、一旦整理する為にExcelに一覧表を使って、情報を記入していきたいとのことでした。

力技で解決

何かいいツールは無いかなと、ざっと調べてみたのですが、良いツールが見つからなかったため、ここは自力で対応するしかないなと考えました。
コマンドプロンプトでtreeコマンドを使えば、フォルダー階層を得ることはできるので、正規表現を使って力技で解決しようと思い、下記の対応を行うことにしました。

まず、treeコマンドで該当フォルダーの一覧を取得します。

	tree /F 対象のフォルダーのパス > 出力ファイル名

00_cmd.png

こうして出来上がったファイルは、見た目上は階層構造になっているのですが、インデントが無いため、このままではExcelへ貼り付けても、並び替えやフィルターの機能を活用することができません。

01_tree.png
そこで、正規表現でインデントを作っていくことにしました。

ファイルに現れる罫線記号「├」「└」「│」と、罫線の後ろについている「  」(半角スペース2つ)が、実質的な階層と等しいため、これをタブに置換します。(ちなみに社内で使用するテキストエディターは自由に選んでよいことになっており、私は秀丸を使用しております)

		├|└|│|  (←※半角スペース2つがある)を\tに置換

02_regexp1.png

罫線記号「─」はフォルダーの先頭についているので、これは「\t■」に置換することでマークを付けます。

		─を\t■に置換

03_regexp2.png

また、これらは「└─」や「│  」といったように、2つセットで使われる為、インデントが冗長になることを防ぐために、タブ2つをタブ1つに置換し、タブの数を圧縮します。

		\t\tを\tに置換

04_regexp3.png

列挙されたファイルの次の行は空行になっている為、これを削除する必要があります。このため、タブのみとなった行を除去します。

		^\t+\nを空欄に置換

05_regexp4.png

こうして、出来上がったテキストをExcelにコピペすることで、フォルダー階層の通りにインデントが付き、さらにフォルダーに■がマークされているファイルが完成します。これで望みの結果を得ることができました。
06_result.png07_excel.png

自社ツール「Unifinity」で解決

というわけで、出来上がったファイルを提出したのですが、その際に「これってUnifinityで出来ないんですかね?」という素朴な疑問を受けました。 確かに、Unifinityを使ってこういった操作ができれば、出来上がったアプリを提供することで、いちいち依頼を受けて作業する必要もなくなりますし、今後、似たような作業が発生した際にも活用できるかもしれません。そこでチャレンジしてみることにしました。

GUIはシンプルに作り、アプリ上に説明文も書いてしまうことにしました。
08_uni.png

処理については先ほどの手順をUnifinityのロジックへ移していくだけなのですが、手動でやっていた内容を、自動化するためにいくつか工夫が必要です。

まず、treeコマンドを実行してフォルダーツリーを得る処理ですが、現在のUnifinityではコマンドプロンプトと密に連携する機能は許可しておりません。 ただし、外部アプリケーションを起動する手段を用意している為、コマンドプロンプトの起動は可能です。 そこで、「フォルダーダイアログを表示して、解析したいフォルダーをユーザーに選択させる」「得たパスを基にコマンド文字列を作成し、クリップボードにコピーする」「コマンドプロンプトを自動起動し、ユーザーには右クリックしてもらう(するとクリップボードから貼り付けが行われる)」「コマンドの結果はテンポラリーファイルとして出力する」 という手を使うことで解決しました。

ユーザーから見たら、フォルダーを選択後、右クリックしてEnterキーを押すだけなので、とても簡単です。これなら難しいことを考えなくてもユーザーに操作をしてもらえそうです。
09_select.png10_unicommand.png

続いて、解析処理の部分です。コマンドの結果はテンポラリーファイルに出力されている為、このファイルをUnifinityで読み取って解析ロジックを動かしていきます。

まず、文字列置換の機能を使って、先ほどと同じように罫線である「├」「└」「│」と半角スペース2つ「  」をタブに置換し、「─」をタブと■に置換していきます。

続いての正規表現ですが、Unifinityには「正規表現で文字列を検索する」という機能があるため、「検索結果にマッチしたものを置換する」という処理を、 検索結果にマッチするものが無くなるまでループで繰り返す、という処理にしました。
11_regexp.png
前半部分は文字の置換、後半部分は進捗率の計算になります。やりたいことを、やりたいとおりにUnifinityのロジックで並べるだけで、煩雑にならずに処理が組めました。

NASのフォルダーツリーは、結構な量になることが予想され、処理を実行してから完了するまでには多少時間がかかりそうです。ユーザーに安心感を与えるためには進捗率の表示が必要になります。 ループの最中は「現在置換を行っている文字列の位置」から「ファイルの文字数」を割ることで、進捗率を得ることができるため、 Unifinityの「Waiting画面表示」を使って待機画面を表示し、そこに進捗率も合わせて表示することにしました。
12_progress.png

こうしてできあがったアプリを使って、いくつかのフォルダーでファイルを出力し、手作業で作ったファイルと同じ内容になることを確認することでテストを完了としました。これで無事に"納品"でき、仕事が一つ完了となりました。

まとめ

今回のアプリで処理している内容は、ほぼバッチのようなものになりますが、GUIが付くことで、ユーザーには手軽なツールであると感じてもらえるかと思います。
また、同じようなことはExcelマクロなどで自動化することもできるとは思いますが、Unifinityの場合は、開発者以外の方であっても簡単な内容ならば修正できるところがポイントとなります。マクロのセキュリティを気にしなくて良いのも利点です。

気になる処理速度ですが、フォルダー数約38,000、ファイル数約80,000、フォルダーツリーにすると約125,000行になるフォルダーでテストしてみたところ、12秒で完了しました。(ちなみに手作業の場合は174秒)
Unifinityはネイティブアプリケーションなので、文字列操作も高速に動作しますし、なにより数クリックで作業が済む点が一番のポイントとなります。

アプリの構築自体は30分ぐらいでした。
業務ロジックの部分をもっと部品化することが出来れば、今後は似たような処理であればさらに短時間で作れるようになるかと思います。 この辺りは今後の開発の課題としていこうと考えております。