MQL4のファイル操作関数を体系的にまとめました。FileOpen()によるファイルオープン、FileClose()によるクローズ、FileWrite()/FileWriteString()による書き込み、FileReadString()/FileReadNumber()による読み込み、FileDelete()によるファイル削除、CSV/テキスト/バイナリの各モード、FileIsExist()によるファイル存在確認、トレードログの保存、設定ファイルの読み込みまで、MT4 EA開発に必要なファイル操作のすべてをコード付きで解説します。
MQL4とMQL5のファイル操作の違い
| 機能 | MQL4 | MQL5 |
|---|---|---|
| 基本関数 | ほぼ同じ | ほぼ同じ |
| ファイルパス | MQL4/Files/フォルダ | MQL5/Files/フォルダ |
| 共通フォルダ | FILE_COMMON フラグ | FILE_COMMON フラグ |
| Unicode | FILE_ANSI / FILE_UNICODE | 同じ |
| フォルダ操作 | FolderCreate/Delete(ビルド600+) | FolderCreate/Delete/Clean |
MQL4のファイル操作はセキュリティ上、MQL4/Files/フォルダ(またはテスター使用時はtester/files/)内でのみ実行できます。このサンドボックスの外にはアクセスできません。
FileOpen — ファイルを開く
int FileOpen(
string file_name, // ファイル名(Files/フォルダ内の相対パス)
int open_flags, // オープンフラグの組み合わせ
short delimiter = '\t', // CSVの区切り文字
uint codepage = CP_ACP // コードページ
);
// 戻り値: ファイルハンドル(失敗時はINVALID_HANDLE)オープンフラグ
| フラグ | 説明 |
|---|---|
| FILE_READ | 読み込み用 |
| FILE_WRITE | 書き込み用 |
| FILE_BIN | バイナリモード |
| FILE_CSV | CSVモード(区切り文字対応) |
| FILE_TXT | テキストモード |
| FILE_ANSI | ANSIエンコーディング |
| FILE_UNICODE | Unicodeエンコーディング |
| FILE_COMMON | 共通フォルダを使用 |
- 通常:
MQL4/Files/フォルダ内のみアクセス可能 - テスター:
tester/files/フォルダにリダイレクトされる - FILE_COMMON: ターミナル共通フォルダ(
AppData/Roaming/MetaQuotes/Terminal/Common/Files/) - サブフォルダの作成:
FolderCreate("subfolder")(ビルド600+) - 絶対パスは指定できない(セキュリティ上の制約)
- 通常:
MQL4/Files/フォルダ内のみアクセス可能 - テスター:
tester/files/フォルダにリダイレクトされる - FILE_COMMON: ターミナル共通フォルダ(
AppData/Roaming/MetaQuotes/Terminal/Common/Files/) - 絶対パスは指定できない(セキュリティ上の制約)
CSVファイルの書き込み
void WriteTradeLog(int ticket, string action, double lots, double price)
{
string filename = "TradeLog_" + Symbol() + ".csv";
int handle = FileOpen(filename, FILE_READ|FILE_WRITE|FILE_CSV, ',');
if(handle == INVALID_HANDLE)
{
Print("ファイルオープン失敗: ", GetLastError());
return;
}
// ファイル末尾に移動
FileSeek(handle, 0, SEEK_END);
// ファイルが空ならヘッダーを書く
if(FileTell(handle) == 0)
FileWrite(handle, "DateTime", "Action", "Symbol", "Ticket",
"Lots", "Price", "Balance", "Equity");
// データ行を書き込み
FileWrite(handle,
TimeToStr(TimeCurrent(), TIME_DATE|TIME_SECONDS),
action,
Symbol(),
ticket,
DoubleToStr(lots, 2),
DoubleToStr(price, Digits),
DoubleToStr(AccountBalance(), 2),
DoubleToStr(AccountEquity(), 2)
);
FileClose(handle);
}CSVファイルの読み込み
void ReadTradeLog()
{
string filename = "TradeLog_" + Symbol() + ".csv";
int handle = FileOpen(filename, FILE_READ|FILE_CSV, ',');
if(handle == INVALID_HANDLE)
{
Print("ファイルが見つかりません");
return;
}
// ヘッダー行をスキップ
string header = FileReadString(handle);
int lineCount = 0;
while(!FileIsEnding(handle))
{
string dateTime = FileReadString(handle);
string action = FileReadString(handle);
string symbol = FileReadString(handle);
int ticket = (int)FileReadNumber(handle);
double lots = FileReadNumber(handle);
double price = FileReadNumber(handle);
double balance = FileReadNumber(handle);
double equity = FileReadNumber(handle);
if(StringLen(dateTime) > 0)
{
Print(dateTime, " ", action, " ", symbol,
" ticket=", ticket, " lots=", lots);
lineCount++;
}
}
FileClose(handle);
Print("読み込み完了: ", lineCount, "行");
}FILE_READ|FILE_WRITEを同時に指定すると、既存ファイルを開いて読み書きできます。FILE_WRITEのみだとファイルが空になります。既存ファイルに追記する場合は、必ずFILE_READ|FILE_WRITEで開いてからFileSeek(handle, 0, SEEK_END)でファイル末尾に移動してください。
FILE_READ|FILE_WRITEを同時に指定すると、既存ファイルを開いて読み書きできます。FILE_WRITEのみだとファイルが空になります。既存ファイルに追記する場合は、必ずFILE_READ|FILE_WRITEで開いてからFileSeek(handle, 0, SEEK_END)でファイル末尾に移動してください。
テキストファイル操作
// テキストファイルへの書き込み
void WriteTextLog(string message)
{
string filename = "EA_Log.txt";
int handle = FileOpen(filename, FILE_READ|FILE_WRITE|FILE_TXT|FILE_ANSI);
if(handle == INVALID_HANDLE) return;
FileSeek(handle, 0, SEEK_END);
FileWriteString(handle,
TimeToStr(TimeCurrent(), TIME_DATE|TIME_SECONDS) + " " + message + "\n");
FileClose(handle);
}
// テキストファイルの全文読み込み
string ReadTextFile(string filename)
{
int handle = FileOpen(filename, FILE_READ|FILE_TXT|FILE_ANSI);
if(handle == INVALID_HANDLE)
return "";
int size = (int)FileSize(handle);
string content = FileReadString(handle, size);
FileClose(handle);
return content;
}バイナリファイル操作
// 構造体をバイナリで保存
struct TradeRecord
{
int ticket;
int type;
double lots;
double openPrice;
datetime openTime;
};
void SaveTradeRecords(TradeRecord &records[], int count)
{
int handle = FileOpen("trades.bin", FILE_WRITE|FILE_BIN);
if(handle == INVALID_HANDLE) return;
// レコード数を最初に保存
FileWriteInteger(handle, count);
for(int i = 0; i < count; i++)
{
FileWriteInteger(handle, records[i].ticket);
FileWriteInteger(handle, records[i].type);
FileWriteDouble(handle, records[i].lots);
FileWriteDouble(handle, records[i].openPrice);
FileWriteInteger(handle, (int)records[i].openTime);
}
FileClose(handle);
}
int LoadTradeRecords(TradeRecord &records[])
{
int handle = FileOpen("trades.bin", FILE_READ|FILE_BIN);
if(handle == INVALID_HANDLE) return 0;
int count = FileReadInteger(handle);
ArrayResize(records, count);
for(int i = 0; i < count; i++)
{
records[i].ticket = FileReadInteger(handle);
records[i].type = FileReadInteger(handle);
records[i].lots = FileReadDouble(handle);
records[i].openPrice = FileReadDouble(handle);
records[i].openTime = (datetime)FileReadInteger(handle);
}
FileClose(handle);
return count;
}ファイルユーティリティ関数
| 関数 | 説明 |
|---|---|
| FileIsExist(filename) | ファイルの存在確認 |
| FileDelete(filename) | ファイルの削除 |
| FileMove(src, dst, flag) | ファイルの移動/リネーム |
| FileCopy(src, flag, dst, flag) | ファイルのコピー |
| FileSize(handle) | ファイルサイズ(バイト) |
| FileTell(handle) | 現在のファイル位置 |
| FileSeek(handle, offset, origin) | ファイル位置の移動 |
| FileFlush(handle) | バッファのフラッシュ |
| FileIsEnding(handle) | ファイル末尾かどうか |
| FileIsLineEnding(handle) | 行末かどうか |
| FolderCreate(path) | フォルダの作成(ビルド600+) |
| FolderDelete(path) | フォルダの削除(ビルド600+) |
void FileUtilityExample()
{
string filename = "test.txt";
// 存在確認
if(FileIsExist(filename))
Print("ファイルが存在します");
else
Print("ファイルが存在しません");
// ファイル削除
if(FileIsExist("old_log.txt"))
FileDelete("old_log.txt");
// フォルダ作成(ビルド600+)
FolderCreate("Logs");
FolderCreate("Logs\\2024");
// 共通フォルダへの書き込み(複数EAで共有)
int handle = FileOpen("shared_data.txt",
FILE_WRITE|FILE_TXT|FILE_COMMON);
if(handle != INVALID_HANDLE)
{
FileWriteString(handle, "共有データ");
FileClose(handle);
}
}実践: 設定ファイルの読み書き
// key=value形式の設定ファイル読み込み
string ReadSetting(string filename, string key, string defaultValue = "")
{
int handle = FileOpen(filename, FILE_READ|FILE_TXT|FILE_ANSI);
if(handle == INVALID_HANDLE)
return defaultValue;
string result = defaultValue;
while(!FileIsEnding(handle))
{
string line = FileReadString(handle);
int eqPos = StringFind(line, "=");
if(eqPos > 0)
{
string k = StringSubstr(line, 0, eqPos);
string v = StringSubstr(line, eqPos + 1);
StringTrimLeft(k); StringTrimRight(k);
StringTrimLeft(v); StringTrimRight(v);
if(k == key)
{
result = v;
break;
}
}
}
FileClose(handle);
return result;
}
// 使用例
void LoadSettings()
{
double riskPercent = StrToDouble(ReadSetting("ea_config.ini", "RiskPercent", "2.0"));
int maxPositions = StrToInteger(ReadSetting("ea_config.ini", "MaxPositions", "3"));
string allowedPairs = ReadSetting("ea_config.ini", "AllowedPairs", "USDJPY,GBPJPY");
Print("Risk: ", riskPercent, "% MaxPos: ", maxPositions, " Pairs: ", allowedPairs);
}ファイル操作関数一覧(MQL5対応表)
| MQL4関数 | MQL5対応 | 説明 |
|---|---|---|
| FileOpen() | FileOpen() | ファイルを開く |
| FileClose() | FileClose() | ファイルを閉じる |
| FileWrite() | FileWrite() | CSVフィールド書き込み |
| FileWriteString() | FileWriteString() | 文字列書き込み |
| FileWriteInteger() | FileWriteInteger() | 整数書き込み |
| FileWriteDouble() | FileWriteDouble() | 浮動小数点書き込み |
| FileReadString() | FileReadString() | 文字列読み込み |
| FileReadNumber() | FileReadNumber() | 数値読み込み |
| FileReadInteger() | FileReadInteger() | 整数読み込み |
| FileReadDouble() | FileReadDouble() | 浮動小数点読み込み |
| FileDelete() | FileDelete() | ファイル削除 |
| FileIsExist() | FileIsExist() | 存在確認 |
| FileSize() | FileSize() | サイズ取得 |
| FileSeek() | FileSeek() | 位置移動 |
| FileTell() | FileTell() | 現在位置取得 |
まとめ
MQL4のファイル操作関数はMQL5とほぼ同じで、移植性が高いカテゴリです。重要なポイントは以下の通りです。
- ファイルはMQL4/Files/フォルダ内でのみ操作可能 — セキュリティサンドボックス
- FileOpen()後は必ずFileClose()する — ファイルハンドルのリークを防ぐ
- FILE_COMMONで複数EA間のデータ共有が可能
- CSVモードはFileWrite()、テキストモードはFileWriteString()を使い分ける
次のステップとして、MQLリファレンス総合ガイドで他のカテゴリも学習しましょう。





