この記事で扱っていること
- ファイル移動で上書きかリネームかを選択させる方法
を紹介しています。
注意:すべてのエラーを確認しているわけではないので、記事の内容を実装する際には自己責任でお願いします。また、エラー配線は適当な部分があるので適宜修正してください。
LabVIEWや他のアプリで作成したデータファイルを扱う場合、時に慎重に扱わないと大切なデータが失われかねないという事態が起こりえます。
特に、ファイルの移動には気を付ける必要があり、もし移動元のファイルと同じファイル名のファイルが移動先に存在している場合には、移動先のファイルが不用意に(意図せず)失われるということになりかねません。
Windowsのファイルエクスプローラでは、同名ファイルがあった場合に、スキップするか上書きするか等の選択肢が出ますが、このような機能をLabVIEWで実装する場合にはどうするか、ということを考えました。
どんな結果になるか
今回は例として、以下のような二つのフォルダがあるとします。
ソース、と呼んでいるのは、ファイルの移動元のフォルダで、ターゲットと呼んでいるのはファイルの移動先のフォルダです。
なので、以下の図の場合、ソースフォルダに入っているa、c、d、f、h、i.txtのファイルを、ターゲットフォルダに移すような場面を想定しています。

プログラムでは、ソースフォルダパスとターゲットフォルダパスを選択できるようにしています。
ソースフォルダパスにあるファイルすべてをターゲットフォルダに移す前提として、もしソースフォルダにあるファイルと同名のファイルがターゲットフォルダにある場合には、ソースフォルダ側のファイルを移さないか、上書きするか、リネームするか等を決定していきます。

プログラムを実行すると、同名ファイルがない場合にはそのままソースからターゲットフォルダへ移りますが、同名ファイルがあるとプロンプトが表示され、どのような操作を行うかを確認してきます。
そもそもファイルの移動をやめるか、ソースフォルダのファイルで、ターゲットフォルダのファイルを上書きするか、あるいはどちらも残すためにソースフォルダのファイルをリネームして移すかを選択します。
今回のプログラムでは、リネーム規則として「(ファイル名)_(日付)moved」という名前にしています(がもちろんここは好みに合わせてカスタマイズできます)。
また、「他全てに同じ内容を適用する」かどうかを決めさせるチェックボックス(ブール)を設けることで、同じ操作を以降全てのファイルに適用するかどうかも決めることができます。

プログラムの構造
全体の構造としては、ソースとターゲットのフォルダをチェックして同じ名前のファイルがないかを探すという操作をForループの自動指標付け機能で繰り返すというシンプルな作りとしています。
そのため、ソースフォルダおよびターゲットフォルダのパスを指定したらフォルダをリスト関数でそれぞれのフォルダの中のファイルの一覧を取得し、Forループに渡しています。
ここで、ファイルの一覧(配列)の自動指標付けを有効にするのはソースフォルダパスに対してだけで、ターゲットフォルダについてのファイルの一覧の配列に対しては自動指標付けを無効にすることに注意してください。
Forループの中で「ターゲットフォルダ内に、ソースフォルダにある特定のファイルと同じ名前のファイルがあるか」を検索させるので、Forループ内では常にターゲットフォルダ内のファイルの情報は配列として扱う必要があるためです。

Forループの中の1D配列検索の結果が-1、つまり一致する名前のファイルが存在しない場合には、Trueケースが実行され、単純に移動の関数を使用します。

一方で同じ名前のファイルがあった場合にはFalseケースが実行され、このときにソースフォルダのファイルをどのように扱うかをユーザーに確認するための機能を持つサブVI、warning_prompt.viが実行されます。
このサブVIで、移動をしないか、上書きするか、あるいはリネームするかを分けます。

このサブVIの処理の内容によってその後の動作が変わります。
実行時に表示されるプロンプトの中で「他全てに同じ内容を適用する」にチェックマークがついた状態でユーザーがどれかの操作を決めると、それ以降はwarning_prompt.viは実行されることなく、決められた操作を繰り返すようになります。
ユーザーが決めた操作である「移動しない」、「上書きする」、あるいは「リネームする」という3択は、後述するサブVIの中身ではブールの情報として扱っていますが、それらのブールの情報を数値に変換してケースストラクチャに渡しています。
その関係上、ケースストラクチャのラベルは「1」、「2」、「4」それぞれに処理を書きます(デフォルトはどれにしてもOK)。

warning prompt.viは以下のようなフロントパネルを持ちます。
実際プログラム実行時に表示するときに余計な部分が表示されているのも微妙なので、ソースやターゲットのファイルパス制御器等は隠れるようにフロントパネルの大きさを調整しておきます。

ブロックダイアグラムは以下の通りです。
メインVIから渡されたソースやターゲットファイルパス制御器の情報を基に、文字列にフォーマット関数でそれっぽい文言を作り表示しています。
イベントは一つしかなく、繰り返しのブール以外のブール制御器が押されるとサブVIが終了するようになっています。(以下の図でイベントケースは一つで、「移動しない」「上書き」「リネーム」の値変更イベントのみです)

プログラム実行時にこのサブVIがユーザーに表示されるように、サブVIのVIプロパティを開いて、ウィンドウの外観カテゴリにて「ダイアログ」あるいは「カスタマイズ」して、実行時にフロントパネルが表示されるように設定しておきます。

同名ファイルの残り個数を表示する
上のプログラムでは、同じ内容の処理を繰り返す場合に「他全て」という表現をしていました。
ただ、場合によっては「あと何個同名ファイルがあるか」を明示した方が便利ということもあるかと思います。

これを行わせるには、まず初めに全体で何個のファイルがソースとターゲットのパスで名前が同じかを知る必要があるため、その処理を行ってから、その情報をサブVIに渡します。
そのために、メインの処理を行うForループの前に、小さいForループで数を数えておきます。
ForループとForループの間にデクリメントを置いていますが、これは「あとN個のファイルに適用する」という「残りのファイル数」を表示している関係上、「今対象になっているファイル」の1つ分を除いた数をNに代入するためです。

warning promptも以下のようにプログラムを書き換えます。
繰り返しのブール制御器に対するプロパティノードで、表示(Visible)プロパティを使用していますが、これは「あとN個に~」の表示のNが0の時にはそもそもこのメッセージを表示する必要がないために、N=0の場合には表示をオフにする目的で使っています。

ファイルの情報を表示する
移動しないか上書きするかなどの判断を行わせる際に、そもそもどういうファイルだっけ、ということがわからないと判断できない場合もあると思います。
ファイル名の情報だけでなく、更新日時だったり、ファイルサイズについても表示しておくと、どのように対応させればいいかがより判断しやすくなります。
そのために、もう少しプロンプトの枠を増やして情報を増やすようにします。

warning prompt.viを以下のように修正します。
基本的にはソースやターゲット用の文字列表示器に表示する文字列を、文字列にフォーマット関数で整えるだけですが、ファイルの情報はファイル/ディレクトリ情報の関数で取得しています。
ただし、この関数で得られるバイトの出力は、ファイルのサイズを「B(バイト)」単位で表示するものであり、実際にはKBやMBほどのファイルサイズでも全てB表記になるので、そのままこのバイト出力を文字列表示器で表示するとわかりにくいかと思い、byte conversion.viという変換のためのサブVIを使用しています。

byte conversion.viは以下のような作りになっていて、B単位の数を1024で割れるだけ割って何回その操作を行ったかでKBなのかMBなのか、といった判定をさせるようにしています。

本記事では、ファイル移動で上書きかリネームかを選択させる方法について紹介しました。
今回はWindowsのファイルエクスプローラのようなものを目指しましたが、アプリケーションによってはそれ以外の選択肢(テキストファイルの中身を統合する、重複したファイルだけ別のフォルダに保存する、など)を付けた方が便利な場合もあるかと思います。
その足掛かりとして、本記事のプログラムが参考になればうれしいです。
ここまで読んでいただきありがとうございました。
コメント