FileMove関数の働き・役割
FileMove関数は、指定されたファイルをローカルフォルダまたは共有フォルダから別のフォルダに移動させるために使用されます。FileMove関数は、ファイルの移動や名称変更を行う際に利用され、特にファイルを他のクライアント端末と共有する必要がある場合に便利です。
ファイルの場所を指定するためのフラグ(common_flag)や、既存のファイルを上書きするかどうかを決定するアクセスモードフラグ(mode_flags)を指定することができ、これによりファイルの管理が柔軟に行えます。
また、この関数を使用する際、MQL5ではセキュリティ上の理由からファイルの操作は制限されています。操作可能なファイルはサンドボックス内に存在し、サンドボックスの外のファイルにアクセスすることはできません。
サンドボックスとは何か?
サンドボックスとは、プログラムの実行やファイルの操作を制限された環境内で行う仕組みのことです。MQL5におけるサンドボックスは、外部のシステムやファイルに対する不正なアクセスや影響を防ぐために設けられています。ファイル操作はこのサンドボックス内に限られ、外部のフォルダやシステムへのアクセスは許可されていません。これにより、取引プラットフォームやコンピュータ全体の安全性が確保されています。
FileMove関数の引数について
bool FileMove(
const string src_file_name, // 移動されるファイルの名称
int common_flag, // 場所
const string dst_file_name, // ターゲットファイルの名称
int mode_flags // アクセスモード
);
FileMove関数は、4つの引数を取ります。それぞれの引数は、ファイルの移動や名称変更を正しく行うために重要な役割を果たします。
1. src_file_name(移動されるファイルの名称)
この引数は、移動または名称変更される元のファイルの名前を指定します。この名前は、ファイルが存在するローカルフォルダまたは共有フォルダ内で特定されます。
2. common_flag(場所)
この引数は、ファイルが存在するフォルダの種類を指定します。次の2つのオプションが利用可能です。
- 0(初期値):ファイルはローカルフォルダ内に存在します。
- FILE_COMMON:ファイルは共有フォルダ(\Terminal\Common\Files)内に存在します。
3. dst_file_name(ターゲットファイルの名称)
この引数は、移動後または名称変更後のファイル名を指定します。移動先のフォルダ内で、この名前で新しいファイルが保存されます。
4. mode_flags(アクセスモード)
この引数は、ファイルの移動や書き換えがどのように行われるかを指定するフラグです。使用できるフラグは2つあります。
- FILE_REWRITE:移動先に同名のファイルが既に存在する場合、ファイルを上書きします。このフラグが指定されていない場合、既存のファイルは上書きされません。
- FILE_COMMON:ファイルを共有フォルダに移動させる際に使用されます。
FileMove関数の戻り値について
FileMove関数は、ファイルの移動や名称変更が成功した場合にtrueを返します。逆に、何らかの理由で操作が失敗した場合はfalseが返されます。
主な失敗原因としては、以下のようなケースがあります。
FileMove関数がfalseを返した場合、GetLastError関数を使ってエラーコードを確認することができ、問題の原因を特定する手助けになります。
FileMove関数を使ったサンプルコード
//--- スクリプトの起動時に入力パラメータのウィンドウを表示する指示
#property script_show_inputs
//--- 入力パラメータ
input ulong InpThresholdSize=20; // ファイルサイズのしきい値(キロバイト単位で指定)
input string InpBigFolderName="big"; // 大きいファイルを保存するフォルダ名
input string InpSmallFolderName="small"; // 小さいファイルを保存するフォルダ名
//+------------------------------------------------------------------+
//| スクリプトの開始を指示する関数 |
//+------------------------------------------------------------------+
void OnStart()
{
string file_name; // 検索結果として見つかったファイルの名前を格納する変数
string filter="*.csv"; // 検索するファイルの種類(ここではCSVファイルを対象とする)
ulong file_size=0; // ファイルサイズ(バイト単位)を格納する変数
int size=0; // 見つかったファイルの数を格納する変数
//--- 現在操作しているファイルのフォルダパスをエキスパートログに出力
PrintFormat("現在 %s\\Files\\ フォルダで作業中", TerminalInfoString(TERMINAL_COMMONDATA_PATH));
//--- 全ての端末に共通のフォルダから最初のCSVファイルを見つけるための検索ハンドルを取得
long search_handle = FileFindFirst(filter, file_name, FILE_COMMON);
//--- FileFindFirst() が成功したかどうかを確認する
if (search_handle != INVALID_HANDLE)
{
//--- 見つかったファイルを順に処理するループ
do
{
//--- ファイルを開く
ResetLastError(); // 前回のエラーをリセット
int file_handle = FileOpen(file_name, FILE_READ | FILE_CSV | FILE_COMMON);
//--- ファイルが正常に開かれたか確認
if (file_handle != INVALID_HANDLE)
{
//--- FileSize関数を使って、開いたファイルのサイズを取得
file_size = FileSize(file_handle);
//--- ファイルを閉じる
FileClose(file_handle);
}
else
{
//--- ファイルが開けなかった場合はエラーメッセージを出力し、次のファイルに進む
PrintFormat("%s ファイルを開けませんでした。エラーコード = %d", file_name, GetLastError());
continue; // 次のループへスキップ
}
//--- ファイルのサイズをエキスパートログに出力
PrintFormat("%s ファイルのサイズは %d バイトです", file_name, file_size);
//--- ファイルを移動するパスを定義(しきい値を基準にフォルダを分ける)
string path;
if (file_size > InpThresholdSize * 1024) // しきい値を超える場合、大きいファイルとして扱う
path = InpBigFolderName + "//" + file_name;
else // しきい値以下の場合、小さいファイルとして扱う
path = InpSmallFolderName + "//" + file_name;
//--- ファイルを指定したフォルダに移動する
ResetLastError(); // 前回のエラーをリセット
if (FileMove(file_name, FILE_COMMON, path, FILE_REWRITE | FILE_COMMON))
{
//--- 移動が成功した場合、エキスパートログにメッセージを出力
PrintFormat("%s ファイルを移動しました", file_name);
}
else
{
//--- 移動に失敗した場合、エラーメッセージを出力
PrintFormat("ファイル移動に失敗しました。エラーコード = %d", GetLastError());
}
} while (FileFindNext(search_handle, file_name)); // 次のファイルが存在するか確認
//--- ファイル検索のためのハンドルを閉じる
FileFindClose(search_handle);
}
else
{
//--- 検索が失敗した場合、エキスパートログにメッセージを出力
Print("ファイルが見つかりませんでした!");
}
}
このサンプルコード全体は、指定されたフォルダ内のすべてのCSVファイルを検索し、そのファイルサイズに応じて大きいファイルと小さいファイルを別々のフォルダに移動するという処理を行います。以下がコード全体の具体的な挙動です。
1. 入力パラメータの設定
ユーザーは、以下の3つの入力パラメータを指定できます。
- InpThresholdSize:ファイルのしきい値サイズ(キロバイト単位)。この値を基準にしてファイルが大きいか小さいかを判断します。
- InpBigFolderName:大きいファイルを移動するフォルダの名前。
- InpSmallFolderName:小さいファイルを移動するフォルダの名前。
2. フォルダ内のCSVファイルを検索
スクリプトが実行されると、まず共通フォルダ内でCSVファイルを検索します。FileFindFirst関数を使用して、最初のCSVファイルを見つけ、その後FileFindNext関数を使って残りのCSVファイルを順次検索します。
3. ファイルの開閉とサイズ取得
見つけたファイルをFileOpen関数で開きます。開いたファイルが正常であれば、FileSize関数を使ってそのファイルのサイズを取得します。ファイルサイズが取得できたら、FileClose関数でファイルを閉じます。
4. ファイルサイズに応じた移動
取得したファイルサイズがしきい値(InpThresholdSize)よりも大きい場合は、大きいファイルとみなし、指定されたフォルダ(InpBigFolderName)に移動します。しきい値以下の場合は、小さいファイルとして、別のフォルダ(InpSmallFolderName)に移動します。
ファイルの移動にはFileMove関数を使用し、移動の成功または失敗に応じてエキスパートログにメッセージが記録されます。
5. 全ファイルの処理
すべてのCSVファイルに対して、この開閉・サイズ取得・移動の処理が行われます。次のファイルが見つかるたびに、同様の処理が繰り返され、全てのファイルが処理されるまでループが続きます。
6. 処理の終了
ファイル検索が終了した後、検索ハンドルが閉じられます。もし検索に失敗し、CSVファイルが見つからなかった場合は、エキスパートログに「ファイルが見つかりませんでした!」というメッセージが出力されます。
結果的に、このスクリプトは以下の動作を行います。
- 指定フォルダ内のCSVファイルを検索し、ファイルサイズに基づいて分類します。
- サイズに応じて、ファイルを「大きいファイル用のフォルダ」または「小さいファイル用のフォルダ」に移動します。
- 各処理の結果やエラーはエキスパートログに記録され、問題があった場合はその内容も確認できます。
サンプルコード解説1:プロパティ命令及びグローバル領域部分
//--- スクリプトの起動時に入力パラメータのウィンドウを表示する指示
#property script_show_inputs
//--- 入力パラメータ
input ulong InpThresholdSize=20; // ファイルサイズのしきい値(キロバイト単位で指定)
input string InpBigFolderName="big"; // 大きいファイルを保存するフォルダ名
input string InpSmallFolderName="small"; // 小さいファイルを保存するフォルダ名
このセクションでは、スクリプトのプロパティ命令およびグローバル領域で定義されている入力パラメータについて解説します。
プロパティ命令:#property script_show_inputs
property script_show_inputs は、スクリプトが実行される際に、入力パラメータのウィンドウを表示するための命令です。この命令を指定することで、スクリプトが実行されたときにユーザーが設定した入力パラメータを確認・編集するウィンドウが自動的に表示されます。
これにより、ユーザーはスクリプトの実行前に設定を変更できるため、複数の条件に柔軟に対応できるようになります。
グローバル領域:入力パラメータ
次に、input キーワードを用いて宣言された入力パラメータについて説明します。入力パラメータは、スクリプト実行時にユーザーが自由に設定できる変数です。これにより、ユーザーは実行ごとに異なる設定を適用できます。
InpThresholdSize
型:ulong型(符号なし長整数)
説明:ファイルサイズのしきい値を指定します。このスクリプトでは、ファイルサイズがこの値を基準にして「大きいファイル」か「小さいファイル」かを分類します。単位はキロバイトで、初期値として20KBに設定されています。
InpBigFolderName
説明:大きいファイルを移動する先のフォルダ名を指定します。初期値は”big”に設定されています。
InpSmallFolderName
説明:小さいファイルを移動する先のフォルダ名を指定します。初期値は”small”に設定されています。
グローバル領域について
このコードでは、入力パラメータがグローバル領域に宣言されています。グローバル領域とは、プログラム全体で参照可能な変数や定数が定義される場所です。これらのパラメータは、スクリプト内のどこからでもアクセスできるため、スクリプトの処理の中で広く使用されます。
サンプルコード解説2:OnStart関数部分その1
//+------------------------------------------------------------------+
//| スクリプトの開始を指示する関数 |
//+------------------------------------------------------------------+
void OnStart()
{
string file_name; // 検索結果として見つかったファイルの名前を格納する変数
string filter="*.csv"; // 検索するファイルの種類(ここではCSVファイルを対象とする)
ulong file_size=0; // ファイルサイズ(バイト単位)を格納する変数
int size=0; // 見つかったファイルの数を格納する変数
//--- 現在操作しているファイルのフォルダパスをエキスパートログに出力
PrintFormat("現在 %s\\Files\\ フォルダで作業中", TerminalInfoString(TERMINAL_COMMONDATA_PATH));
//--- 全ての端末に共通のフォルダから最初のCSVファイルを見つけるための検索ハンドルを取得
long search_handle = FileFindFirst(filter, file_name, FILE_COMMON);
このセクションでは、OnStart関数の前半部分について解説します。OnStart関数は、スクリプトが実行された際に最初に呼び出される関数で、ここでファイルの検索や初期設定が行われます。
変数の宣言
OnStart関数の最初でいくつかの変数が宣言されています。
file_name
説明:検索結果として見つかったファイル名を格納するための変数です。この変数には、FileFindFirst関数やFileFindNext関数で見つけたファイルの名前が代入されます。
filter
説明:検索対象のファイル形式を指定するフィルタです。この例では、*.csvというフィルタが指定されており、CSV形式のファイルを対象にしています。フィルタによって特定の拡張子を持つファイルのみが検索対象となります。
file_size
型:ulong型(符号なし長整数)
説明:ファイルのサイズをバイト単位で格納する変数です。この変数に、FileSize関数を使って取得したファイルサイズを代入します。
size
型:int型(整数)
説明:見つかったファイルの数を格納するための変数です。このコードではまだ使用されていませんが、ファイル数のカウントやその他の処理に活用することが可能です。
エキスパートログへの出力
PrintFormat関数を使用して、現在操作しているフォルダのパスをエキスパートログに出力しています。TerminalInfoString関数を使用して、ファイルの共通フォルダパスを取得し、その情報をログに記録することで、スクリプトが正しい場所で実行されているかを確認することができます。
ファイル検索の開始
FileFindFirst関数を使用して、指定されたフィルタ(この場合は*.csv)に基づいて、最初のファイルを検索しています。検索が成功すると、ファイル名がfile_nameに格納され、検索ハンドルがsearch_handleに返されます。この検索ハンドルは、後続の処理で検索を続行する際に使用します。
サンプルコード解説3:OnStart関数部分その2
//--- FileFindFirst() が成功したかどうかを確認する
if (search_handle != INVALID_HANDLE)
{
//--- 見つかったファイルを順に処理するループ
do
{
//--- ファイルを開く
ResetLastError(); // 前回のエラーをリセット
int file_handle = FileOpen(file_name, FILE_READ | FILE_CSV | FILE_COMMON);
//--- ファイルが正常に開かれたか確認
if (file_handle != INVALID_HANDLE)
{
//--- FileSize関数を使って、開いたファイルのサイズを取得
file_size = FileSize(file_handle);
//--- ファイルを閉じる
FileClose(file_handle);
}
このセクションでは、OnStart関数内のファイル操作部分について解説します。ここでは、ファイルの開閉やサイズの取得といった基本的なファイル操作が行われます。
FileFindFirst関数の結果確認
まず、FileFindFirst関数によってファイルが正常に見つかったかを確認します。search_handleがINVALID_HANDLEでない場合、ファイル検索が成功したことを意味し、次に進みます。この後、do-whileループが開始され、見つかったすべてのファイルに対して処理を実行します。
ファイルの操作
ファイルを開く
ループ内で、まずFileOpen関数を使用してファイルを開きます。ファイルを開く際には、FILE_READ(読み取り専用)、FILE_CSV(CSV形式ファイル)、およびFILE_COMMON(全端末に共通のフォルダ内のファイル)というフラグが指定されています。
- FILE_READ: ファイルを読み取るために開きます。
- FILE_CSV: ファイルのフォーマットをCSVファイルと指定します。
- FILE_COMMON: 全端末で共通のフォルダ内にあるファイルを対象とします。
エラーリセット
ファイルを開く前に、ResetLastError関数を使用して、以前のエラーコードをリセットします。これにより、最新のエラー状態が取得できるようになります。
正常にファイルが開かれたか確認
ファイルが正常に開かれたかどうかは、file_handleがINVALID_HANDLEでないかを確認することで判断されます。INVALID_HANDLEが返された場合、ファイルのオープンに失敗しているため、その場合のエラーメッセージは後の処理で記録されます。
FileSize関数によるファイルサイズの取得
ファイルが正常に開かれた場合は、次にFileSize関数を使用して、開かれたファイルのサイズをバイト単位で取得します。取得したサイズは、file_size変数に格納されます。
ファイルを閉じる
ファイルのサイズを取得した後、必ずFileClose関数を使用してファイルを閉じます。ファイルを適切に閉じることで、システムリソースが解放され、他の操作に支障が出ることを防ぎます。
サンプルコード解説4:OnStart関数部分その3
else
{
//--- ファイルが開けなかった場合はエラーメッセージを出力し、次のファイルに進む
PrintFormat("%s ファイルを開けませんでした。エラーコード = %d", file_name, GetLastError());
continue; // 次のループへスキップ
}
//--- ファイルのサイズをエキスパートログに出力
PrintFormat("%s ファイルのサイズは %d バイトです", file_name, file_size);
//--- ファイルを移動するパスを定義(しきい値を基準にフォルダを分ける)
string path;
if (file_size > InpThresholdSize * 1024) // しきい値を超える場合、大きいファイルとして扱う
path = InpBigFolderName + "//" + file_name;
else // しきい値以下の場合、小さいファイルとして扱う
path = InpSmallFolderName + "//" + file_name;
このセクションでは、OnStart関数内でファイルの開閉エラー処理や、ファイルのサイズに基づいた分類と移動に関する処理を解説します。
ファイルの開閉エラー処理
ファイルが開けなかった場合、file_handleがINVALID_HANDLEであることを確認します。この場合、elseブロックに入り、PrintFormat関数を使用して、エラーメッセージをエキスパートログに出力します。エラーメッセージには、開けなかったファイルの名前と、GetLastError関数で取得したエラーコードが含まれます。
その後、continue文を使用して、現在のループをスキップし、次のファイルの処理に進みます。これにより、エラーが発生してもスクリプトの実行が中断されず、次のファイルの処理が継続されます。
ファイルサイズのログ出力
ファイルが正常に開かれ、FileSize関数によってファイルサイズが取得された場合、次にそのサイズをエキスパートログに出力します。PrintFormat関数を使い、ファイルの名前とサイズをバイト単位で表示します。
ファイルの移動パスの定義
取得したファイルサイズを基に、ファイルを分類する処理が行われます。ここでは、InpThresholdSize(キロバイト単位で指定されるしきい値)を基準にして、ファイルサイズがそのしきい値を超えているかどうかで、ファイルの移動先フォルダを決定します。
- ファイルサイズがInpThresholdSizeを超える場合、大きいファイルとして扱い、InpBigFolderNameフォルダに移動します。
- ファイルサイズがしきい値以下の場合、小さいファイルとして扱い、InpSmallFolderNameフォルダに移動します。
移動先のフォルダパスは、ファイル名とフォルダ名を結合して作成されます。
サンプルコード解説5:OnStart関数部分その4
//--- ファイルを指定したフォルダに移動する
ResetLastError(); // 前回のエラーをリセット
if (FileMove(file_name, FILE_COMMON, path, FILE_REWRITE | FILE_COMMON))
{
//--- 移動が成功した場合、エキスパートログにメッセージを出力
PrintFormat("%s ファイルを移動しました", file_name);
}
else
{
//--- 移動に失敗した場合、エラーメッセージを出力
PrintFormat("ファイル移動に失敗しました。エラーコード = %d", GetLastError());
}
} while (FileFindNext(search_handle, file_name)); // 次のファイルが存在するか確認
このセクションでは、OnStart関数内のファイル移動処理と、次のファイルへの処理の流れについて解説します。
ファイルの移動処理
ファイルサイズに応じた移動先フォルダが決定された後、FileMove関数を使用してファイルを新しい場所に移動します。FileMove関数は、次の引数を受け取ります。
- file_name: 移動するファイルの名前。
- FILE_COMMON: 移動元のファイルが共通フォルダにあることを示すフラグ。
- path: 移動先のフォルダパス。これは前の処理で、ファイルサイズに応じて決定されたパスです。
- FILE_REWRITE | FILE_COMMON: 移動先に同名のファイルがあった場合、上書きするためのフラグ。
エラーハンドリング
ファイルを移動する前に、ResetLastError関数を呼び出して前回のエラー状態をリセットします。これにより、新しいエラーが正しく検出できるようになります。
移動が成功した場合、PrintFormat関数を使用して、移動したファイルの名前をエキスパートログに出力します。逆に、移動に失敗した場合は、GetLastError関数を用いてエラーコードを取得し、そのエラーコードと共にエラーメッセージをエキスパートログに出力します。
次のファイルの処理
do-whileループの最後で、FileFindNext関数を使用して、次のファイルが存在するかを確認します。もし次のファイルが見つかれば、ループの先頭に戻って同じ処理(ファイルの開閉、サイズの取得、移動)を行います。次のファイルが存在しない場合は、ループが終了します。
サンプルコード解説6:OnStart関数部分その5
//--- ファイル検索のためのハンドルを閉じる
FileFindClose(search_handle);
}
else
{
//--- 検索が失敗した場合、エキスパートログにメッセージを出力
Print("ファイルが見つかりませんでした!");
}
}
このセクションでは、OnStart関数の最後の部分で行われているファイル検索の終了処理について解説します。
FileFindClose関数によるハンドルの閉鎖
すべてのファイルの処理が完了した後、FileFindClose関数を使用して、ファイル検索に使用したsearch_handleを閉じます。検索ハンドルは、ファイル検索を行うためにFileFindFirst関数やFileFindNext関数で使用されており、このハンドルを閉じることでシステムリソースが解放されます。
ハンドルを閉じないままにしておくと、システムリソースの無駄遣いとなり、他のファイル操作に影響を与える可能性があるため、必ず最後に閉じる必要があります。
エラーメッセージの出力
もしファイル検索が失敗し、FileFindFirst関数がINVALID_HANDLEを返した場合、検索が失敗したことを示しています。この場合は、elseブロックに入り、Print関数を使って「ファイルが見つかりませんでした!」というメッセージをエキスパートログに出力します。
これにより、ユーザーはファイルが存在しなかったことを確認でき、スクリプトの実行結果を把握できます。
コメント