FolderClean関数の働き・役割
FolderClean関数は、指定されたフォルダ内の全てのファイルを削除するために使用されます。この関数は、フォルダのパスを引数として受け取り、その中にある全てのファイルやサブディレクトリを削除します。
セキュリティ上、MQL5ではファイルの扱いが制限されており、外部のフォルダやシステムディレクトリを操作することはできません。そのため、FolderClean関数はMQL5の「ファイルサンドボックス」と呼ばれる特定の領域に対してのみ動作します。この領域には、MQL5/Filesディレクトリやテスト環境のMQL5/Tester/Filesディレクトリが含まれます。
実行すると、削除されたファイルやフォルダは復元できないため、特に重要なデータが含まれるフォルダを扱う際には慎重な使用が求められます。
FolderClean関数の引数について
bool FolderClean(
string folder_name, // 削除されるフォルダの名称
int common_flag=0 // 範囲
);
FolderClean関数は、2つの引数を取ります。以下に詳細を説明します。
1つ目の引数
folder_name(フォルダ名)
この引数は、削除されるファイルが格納されているフォルダの名前を指定します。フォルダのパスは絶対パスであり、MQL5のサンドボックス内のパスを指定する必要があります。例えば、「MQL5/Files/demo_folder」のようにフォルダパスを記述します。
2つ目の引数
common_flag(共有フラグ、初期値は0)
この引数は、操作対象のディレクトリの位置を指定します。デフォルトの値は0であり、この場合フォルダはローカルフォルダ、すなわち「MQL5/Files」または「MQL5/Tester/Files」内に存在する必要があります。
common_flagがFILE_COMMONの場合、フォルダはすべてのクライアント端末で共有される「Terminal\Common\Files」フォルダ内に存在します。
FolderClean関数の戻り値について
FolderClean関数は、指定されたフォルダ内のファイルを削除できたかどうかを判定し、その結果を真偽値で返します。
- 削除に成功した場合は「true」が返されます。
- 何らかの理由で削除に失敗した場合は「false」が返されます。
たとえば、指定されたフォルダが存在しない場合や、サンドボックスの外部フォルダを指定している場合、削除操作が失敗し、戻り値は「false」になります。
FolderClean関数を使ったサンプルコード
//--- スクリプトの起動時に入力パラメータのウィンドウを表示する
#property script_show_inputs
//--- 入力パラメータ
input string foldername="demo_folder"; // フォルダ名を指定。この例では「demo_folder」というフォルダをMQL5/Files内に作成
input int files=5; // 作成および削除するファイルの数を指定。デフォルトは5
//+------------------------------------------------------------------+
//| スクリプトプログラムを開始する関数 |
//+------------------------------------------------------------------+
void OnStart()
{
//--- ファイル名の共通部分を定義
string name="testfile";
//--- 指定された数だけファイルを作成する
for(int N=0;N<files;N++) // Nが0から指定されたファイル数までループ
{
//--- ファイル名を作成。「demo_folder\testfileN.txt」という形式で保存される
string filemane=StringFormat("%s\\%s%d.txt",foldername,name,N);
//--- ファイルを書き込みモードで開く。このときフォルダが自動的に作成される
int handle=FileOpen(filemane,FILE_WRITE);
//--- FileOpen関数が成功したか確認する
if(handle==INVALID_HANDLE) // ファイルの作成に失敗した場合
{
//--- エラーメッセージをエキスパートログに出力
PrintFormat("ファイル %s の作成に失敗しました。エラーコード: %d",filemane,GetLastError());
//--- エラーコードをリセット
ResetLastError();
}
else // ファイルが正常に作成された場合
{
//--- 成功メッセージをエキスパートログに出力
PrintFormat("ファイル %s は正常に作成されました",filemane);
//--- ファイルを閉じる
FileClose(handle);
}
}
//--- フォルダ内のファイル数をチェックする
int k=FilesInFolder(foldername+"\\*.*",0); // 指定されたフォルダ内の全ファイルを数える
PrintFormat("フォルダ %s 内には合計 %d 個のファイルがあります",foldername,k);
//--- ダイアログボックスを表示して、ユーザーに削除確認を行う
int choice=MessageBox(StringFormat("%d 個のファイルをフォルダ %s から削除しますか?",k,foldername),
"フォルダ内のファイルの削除確認",
MB_YESNO|MB_ICONQUESTION); // 「はい(Y)」 と 「いいえ(N)」 の2つのボタン
ResetLastError();
//--- ユーザーが「はい(Y)」を選択した場合の処理
if(choice==IDYES)
{
//--- ファイル削除を開始する
PrintFormat("フォルダ %s 内の全ファイルを削除します",foldername);
//--- FolderClean関数を使用してフォルダ内の全ファイルを削除
if(FolderClean(foldername,0))
//--- 削除成功後、残っているファイル数を確認
PrintFormat("ファイルは正常に削除されました。フォルダ %s に残っているファイル数は %d です",
foldername,
FilesInFolder(foldername+"\\*.*",0));
else
//--- 削除に失敗した場合のエラーメッセージをエキスパートログに出力
PrintFormat("フォルダ %s 内のファイル削除に失敗しました。エラーコード %d",foldername,GetLastError());
}
else // ユーザーが「いいえ(N)」を選択した場合
PrintFormat("ファイル削除をキャンセルしました");
}
//+------------------------------------------------------------------+
//| 指定されたフォルダ内のファイル数を返す関数 |
//+------------------------------------------------------------------+
int FilesInFolder(string path,int flag)
{
int count=0; // ファイル数のカウンタ
long handle; // ファイル検索ハンドル
string filename; // 見つかったファイルの名前を格納する変数
//--- フォルダ内で最初のファイルを検索
handle=FileFindFirst(path,filename,flag);
//--- ファイルが見つかった場合
if(handle!=INVALID_HANDLE)
{
//--- 見つかったファイルの名前をエキスパートログに出力
PrintFormat("ファイル %s が見つかりました",filename);
//--- ファイル数カウンタを1つ増やす
count++;
//--- 次のファイルを検索
while(FileFindNext(handle,filename))
{
//--- 見つかったファイルの名前をエキスパートログに出力
PrintFormat("ファイル %s が見つかりました",filename);
//--- ファイル数カウンタを増加
count++;
}
//--- 検索が終了したらハンドルを閉じる
FileFindClose(handle);
}
else // ハンドル取得に失敗した場合
{
//--- エラーメッセージをエキスパートログに出力
PrintFormat("フォルダ %s 内のファイル検索に失敗しました",path);
}
//--- ファイル数を返す
return count;
}
サンプルコード解説1:グローバル領域部分
//--- スクリプトの起動時に入力パラメータのウィンドウを表示する
#property script_show_inputs
//--- 入力パラメータ
input string foldername="demo_folder"; // フォルダ名を指定。この例では「demo_folder」というフォルダをMQL5/Files内に作成
input int files=5; // 作成および削除するファイルの数を指定。デフォルトは5
このセクションでは、スクリプトの最初に定義されているグローバル領域の部分について解説します。
スクリプト起動時に入力パラメータのウィンドウを表示
property script_show_inputs は、スクリプトが実行された際に入力パラメータのウィンドウを自動的に表示するための設定です。これにより、スクリプトを実行する前にユーザーがパラメータを設定できるようになります。
入力パラメータの定義
次に、入力パラメータが定義されています。
- foldername
foldername は、フォルダの名前を指定するための入力パラメータです。この例では初期値として「demo_folder」が設定されており、ファイルの作成や削除の対象となるフォルダは「MQL5/Files/demo_folder」になります。ユーザーはスクリプト実行前にこの値を変更して、任意のフォルダ名を指定することができます。 - files
files は、作成および削除されるファイルの数を指定するための整数型の入力パラメータです。初期値は5で、この値をもとに、後の処理で指定された数のファイルが作成され、削除対象として扱われます。
グローバル領域の役割
このコードのグローバル領域では、主にスクリプトの動作に必要な設定と入力パラメータが定義されています。これにより、スクリプト実行時にユーザーが動的にパラメータを指定でき、柔軟な操作が可能になります。また、foldernameとfilesの値は後の関数で使用され、フォルダ名や作成・削除されるファイル数を動的に設定することができます。
サンプルコード解説2:OnStart関数部分その1
//+------------------------------------------------------------------+
//| スクリプトプログラムを開始する関数 |
//+------------------------------------------------------------------+
void OnStart()
{
//--- ファイル名の共通部分を定義
string name="testfile";
//--- 指定された数だけファイルを作成する
for(int N=0;N<files;N++) // Nが0から指定されたファイル数までループ
{
//--- ファイル名を作成。「demo_folder\testfileN.txt」という形式で保存される
string filemane=StringFormat("%s\\%s%d.txt",foldername,name,N);
//--- ファイルを書き込みモードで開く。このときフォルダが自動的に作成される
int handle=FileOpen(filemane,FILE_WRITE);
//--- FileOpen関数が成功したか確認する
if(handle==INVALID_HANDLE) // ファイルの作成に失敗した場合
{
//--- エラーメッセージをエキスパートログに出力
PrintFormat("ファイル %s の作成に失敗しました。エラーコード: %d",filemane,GetLastError());
//--- エラーコードをリセット
ResetLastError();
}
else // ファイルが正常に作成された場合
{
//--- 成功メッセージをエキスパートログに出力
PrintFormat("ファイル %s は正常に作成されました",filemane);
//--- ファイルを閉じる
FileClose(handle);
}
}
このセクションでは、スクリプトの中心となる OnStart関数の最初の部分について解説します。この関数はスクリプト実行時に呼び出され、指定されたフォルダ内にファイルを作成する処理が行われます。
ファイル名の共通部分を定義
まず、name という変数に「testfile」という文字列が格納されます。これは、後に作成するファイルの名前に使用される共通部分です。ファイル名は「testfileN.txt」の形式で保存され、Nはループの回数によって異なる数字が付加されます。
指定された数だけファイルを作成
次に、forループを使用して指定された数だけファイルを作成します。このループは、files パラメータで指定された回数だけ繰り返され、Nが0から始まり、ファイル数分だけインクリメントされていきます。
ファイル名の作成
ループ内では、StringFormat関数を使ってファイル名が動的に作成されます。このファイル名は「demo_folder\testfileN.txt」の形式で、Nにはループの回数に対応する数値が入ります。foldername 変数はユーザーが指定したフォルダ名であり、そこに「testfile」とNを組み合わせてファイル名が構成されます。
ファイルの作成
次に、FileOpen関数を使って、ファイルを指定された名前で作成し、書き込みモードで開きます。このとき、フォルダが存在しない場合は自動的に作成されます。FileOpen関数が成功すれば、ファイルのハンドルが返され、失敗すればINVALID_HANDLEが返されます。
エラーハンドリング
FileOpen関数が失敗した場合、INVALID_HANDLEが返され、エラーメッセージがエキスパートログに出力されます。GetLastError関数を使ってエラーコードが取得され、その後ResetLastError関数でエラー状態がリセットされます。
成功時の処理
ファイルの作成が成功した場合、ファイル名とともに成功メッセージがエキスパートログに出力されます。その後、FileClose関数を使用してファイルが閉じられ、リソースが解放されます。
この部分では、主にファイルの作成とエラーハンドリングに関する基本的な処理が行われています。
サンプルコード解説3:OnStart関数部分その2
//--- フォルダ内のファイル数をチェックする
int k=FilesInFolder(foldername+"\\*.*",0); // 指定されたフォルダ内の全ファイルを数える
PrintFormat("フォルダ %s 内には合計 %d 個のファイルがあります",foldername,k);
//--- ダイアログボックスを表示して、ユーザーに削除確認を行う
int choice=MessageBox(StringFormat("%d 個のファイルをフォルダ %s から削除しますか?",k,foldername),
"フォルダ内のファイルの削除確認",
MB_YESNO|MB_ICONQUESTION); // 「はい(Y)」 と 「いいえ(N)」 の2つのボタン
ResetLastError();
このセクションでは、OnStart関数の続きとなるフォルダ内のファイル数確認と、削除確認を行う部分について解説します。
フォルダ内のファイル数をチェックする
まず、FilesInFolder関数を使用して、指定されたフォルダ内に存在するファイルの数を確認します。foldername 変数に指定されたフォルダパスに「\.」を追加することで、そのフォルダ内の全てのファイルを対象に検索を行います。この結果、ファイルの総数が k 変数に格納されます。PrintFormat関数を使って、フォルダ名とファイルの総数がエキスパートログに出力され、フォルダ内にあるファイルの確認ができるようになっています。
ダイアログボックスを表示して削除確認
次に、MessageBox関数を使用して、ユーザーに対してフォルダ内のファイルを削除するかどうかを尋ねるダイアログボックスを表示します。このダイアログでは、フォルダ内にあるファイルの数とフォルダ名が表示され、「はい(Y)」と「いいえ(N)」の2つの選択肢が提示されます。ユーザーが「はい(Y)」を選択した場合は、削除処理が実行され、「いいえ(N)」を選択した場合は削除がキャンセルされます。
ダイアログボックスが表示された後、ResetLastError関数が呼び出され、エラーステータスがリセットされます。これにより、他の処理に影響を与えないようにしています。
この部分では、ユーザーに対してファイル削除の確認を促し、意図しない削除を防ぐための対話型処理が組み込まれています。
サンプルコード解説4:OnStart関数部分その3
//--- ユーザーが「はい(Y)」を選択した場合の処理
if(choice==IDYES)
{
//--- ファイル削除を開始する
PrintFormat("フォルダ %s 内の全ファイルを削除します",foldername);
//--- FolderClean関数を使用してフォルダ内の全ファイルを削除
if(FolderClean(foldername,0))
//--- 削除成功後、残っているファイル数を確認
PrintFormat("ファイルは正常に削除されました。フォルダ %s に残っているファイル数は %d です",
foldername,
FilesInFolder(foldername+"\\*.*",0));
else
//--- 削除に失敗した場合のエラーメッセージをエキスパートログに出力
PrintFormat("フォルダ %s 内のファイル削除に失敗しました。エラーコード %d",foldername,GetLastError());
}
else // ユーザーが「いいえ(N)」を選択した場合
PrintFormat("ファイル削除をキャンセルしました");
}
このセクションでは、OnStart関数の最後の部分である、ユーザーの選択に基づくファイル削除処理について解説します。
ユーザーが「はい(Y)」を選択した場合の処理
ダイアログボックスでユーザーが「はい(Y)」を選択した場合、削除処理が開始されます。選択内容は、choice 変数で確認され、「IDYES」に対応している場合は、ファイル削除処理が実行されます。
削除開始メッセージの出力
まず、PrintFormat関数を使って、フォルダ内の全ファイルが削除されることをエキスパートログに出力します。これは、削除処理の開始を通知するためのメッセージです。
FolderClean関数によるファイル削除
次に、FolderClean関数を使用して、指定されたフォルダ内の全ファイルを削除します。ここでは、フォルダ名と共に共通フラグ(common_flag)の値として 0 が指定されています。これにより、ローカルフォルダ内のファイルが対象になります。
削除成功時の処理
FolderClean関数が正常に動作し、ファイルが削除された場合は、再度フォルダ内の残りファイル数を FilesInFolder関数を使って確認します。この結果、削除後のフォルダ内ファイル数がエキスパートログに出力されます。もし削除が成功すれば、フォルダ内のファイルはすべて削除されているはずなので、残りファイル数は0になります。
削除失敗時の処理
もしFolderClean関数が失敗した場合は、エラーメッセージがエキスパートログに出力されます。GetLastError関数を使用して、削除処理が失敗した原因となるエラーコードを取得し、エラーメッセージに付加して出力しています。
ユーザーが「いいえ(N)」を選択した場合
ダイアログボックスでユーザーが「いいえ(N)」を選択した場合は、削除処理がキャンセルされます。この場合、ファイル削除を中止した旨がエキスパートログに出力されます。
この部分では、ユーザーの選択に基づいて安全にファイル削除を実行する処理が行われています。削除処理が失敗した場合のエラーハンドリングも適切に組み込まれており、スクリプトの信頼性を高めています。
サンプルコード解説5:FilesInFolder関数(オリジナル関数)その1
//+------------------------------------------------------------------+
//| 指定されたフォルダ内のファイル数を返す関数 |
//+------------------------------------------------------------------+
int FilesInFolder(string path,int flag)
{
int count=0; // ファイル数のカウンタ
long handle; // ファイル検索ハンドル
string filename; // 見つかったファイルの名前を格納する変数
//--- フォルダ内で最初のファイルを検索
handle=FileFindFirst(path,filename,flag);
このセクションでは、サンプルコード内で定義されているオリジナル関数である FilesInFolder関数について解説します。この関数は、指定されたフォルダ内に存在するファイルの数を返す役割を持ちます。MQL5の標準関数ではなく、独自に作成した関数です。
引数の役割
- path
path は、フォルダ内のファイルを検索するためのパスを指定します。この引数は、検索対象のフォルダパスを表し、サンドボックス内のパスを指定する必要があります。例えば、”MQL5/Files/demo_folder”のように指定することで、そのフォルダ内のファイルを対象に検索が行われます。 - flag
flag は、ファイル検索時のオプションを指定するための引数です。ファイル検索にどのような制限を加えるかを制御する目的で使用されます。通常は0が指定され、全てのファイルを検索する場合に使用されます。このフラグを変更することで、特定の条件に合致するファイルのみを検索対象にすることが可能です。
ファイル数のカウンタと検索ハンドル
関数内部では、まずファイルの数をカウントするための count 変数が初期化されます。この変数はフォルダ内にあるファイルの総数を保持します。
また、FileFindFirst関数でファイルを検索するために、検索ハンドルを取得するための handle 変数が宣言されます。handle は、ファイル検索が成功した場合、検索のための識別子として返され、後続のファイル検索処理で使用されます。
検索対象ファイル名の格納
次に、検索によって見つかったファイル名を格納するための filename 変数が宣言されています。この変数には、FileFindFirst関数やFileFindNext関数が見つけたファイル名が一時的に格納され、ログ出力や処理に使用されます。
最初のファイルを検索
FileFindFirst関数を使って、指定された path に基づき最初のファイルを検索します。この関数は、最初のファイルが見つかった場合、handle にその結果を格納し、filename 変数にはファイル名が代入されます。ファイルが見つからなかった場合、INVALID_HANDLEが返され、エラーが発生したことを示します。
サンプルコード解説6:FilesInFolder関数(オリジナル関数)その2
//--- ファイルが見つかった場合
if(handle!=INVALID_HANDLE)
{
//--- 見つかったファイルの名前をエキスパートログに出力
PrintFormat("ファイル %s が見つかりました",filename);
//--- ファイル数カウンタを1つ増やす
count++;
//--- 次のファイルを検索
while(FileFindNext(handle,filename))
{
//--- 見つかったファイルの名前をエキスパートログに出力
PrintFormat("ファイル %s が見つかりました",filename);
//--- ファイル数カウンタを増加
count++;
}
//--- 検索が終了したらハンドルを閉じる
FileFindClose(handle);
}
ファイルが見つかった場合の処理
ファイル検索が成功し、最初のファイルが見つかった場合、handle が INVALID_HANDLEでないことを確認して、処理を開始します。
まず、見つかったファイルの名前が filename 変数に格納され、それをPrintFormat関数を使ってエキスパートログに出力します。これにより、どのファイルが見つかったかを確認することができます。
その後、ファイル数をカウントするために、count 変数の値を1つ増加させます。この count 変数は、フォルダ内のファイル数を正確に記録するために使用されます。
次のファイルを検索する
次に、while ループを使用して、同じフォルダ内で次のファイルを検索します。FileFindNext関数が呼び出されるたびに、次のファイルを検索し、見つかったファイルの名前が filename 変数に再度格納されます。
見つかったファイルの名前は毎回 PrintFormat関数でログに出力され、ファイルが確認されるたびに count 変数を再度インクリメントして、ファイル数を正確にカウントします。
検索終了後の処理
すべてのファイルが検索され終わると、FileFindClose関数を呼び出して検索ハンドルを閉じます。この操作を行うことで、ファイル検索に使用したリソースが解放され、不要なリソース消費を防ぎます。
これらの処理により、指定されたフォルダ内のすべてのファイルを検索し、正確なファイル数をカウントすることができます。
サンプルコード解説7:FilesInFolder関数(オリジナル関数)その3
else // ハンドル取得に失敗した場合
{
//--- エラーメッセージをエキスパートログに出力
PrintFormat("フォルダ %s 内のファイル検索に失敗しました",path);
}
//--- ファイル数を返す
return count;
}
ハンドル取得に失敗した場合の処理
FileFindFirst関数でファイル検索を開始した際、もしハンドルが取得できなかった場合は、INVALID_HANDLEが返されます。この状況は、指定されたフォルダにファイルが存在しないか、フォルダ自体が見つからない場合などに発生します。
ハンドル取得に失敗した際には、PrintFormat関数を使ってエラーメッセージをエキスパートログに出力します。このメッセージには、検索対象のフォルダパス(path)が含まれており、どのフォルダで問題が発生したかを確認することができます。このエラーメッセージにより、ユーザーはフォルダの指定やファイルの存在について確認する手がかりを得ることができます。
ファイル数を返す
最後に、count 変数の値を返します。この変数には、検索によって見つかったファイルの数が格納されており、FilesInFolder関数の呼び出し元で使用されます。ファイルが見つからなかった場合でも、count の初期値は0であるため、返される値は正確です。
このようにして、FilesInFolder関数は指定されたフォルダ内のファイル数を返す役割を果たします。エラー発生時にはエラーログが出力され、正確な情報が得られるよう設計されています。