MQL5 FileOpen Guide: Reading & Writing CSV Files in MetaTrader 5
Use MQL5 FileOpen flags, explicit UTF-8 encoding and delimiter checks to write and read a small CSV example. Learn the terminal and Common Files sandbox locations, overwrite versus append behavior, and why a sample file is not a trade-history export.
What this MQL5 guide covers
FileOpen returns a handle or INVALID_HANDLE; check write results as well as open results.
FILE_COMMON selects another allowed sandbox. It does not permit arbitrary filesystem access.
FILE_CSV defaults to a tab delimiter. Pass a comma explicitly when that is your file format.
This script writes synthetic six-column records, closes the file and reads it back. It places no trades and does not export account history.
FileOpen Function Signature and Bitmask Flags
MQL5 provides low-level file input/output through the FileOpen function. It opens files in text, binary, or delimited CSV mode, controlling access permissions and sharing policies.
| Flag | Value Type | Purpose |
|---|---|---|
| FILE_READ | Open flag | Opens file for reading input data |
| FILE_WRITE | Open flag | Opens file for writing (creates or overwrites existing file) |
| FILE_CSV | Format flag | Specifies comma/delimited text file where FileWrite inserts delimiters automatically |
| FILE_ANSI | Encoding flag | Uses the selected code page; combine FILE_ANSI with CP_UTF8 explicitly for this UTF-8 example |
| FILE_COMMON | Location flag | Directs path to shared Common\Files directory across all MT5 terminals |
| FILE_SHARE_READ | Sharing flag | Allows other applications or EAs to read the file simultaneously |
Terminal Sandbox vs FILE_COMMON Directory
For security reasons, MetaTrader 5 isolates file operations within dedicated directory sandboxes. Without FILE_COMMON, files are written to [Terminal Data Folder]\MQL5\Files. In Strategy Tester the default root is the testing agent directory instead. These are MQL5 path restrictions, not a claim that OS tools cannot read the files.
FILE_COMMON selects the shared Common Files sandbox. Find the root with TerminalInfoString(TERMINAL_COMMONDATA_PATH), then its Files subfolder. External readers need the correct location, encoding and sharing permissions; concurrent writers still require coordination.
- Local Sandbox: FileOpen("log.csv", FILE_WRITE | FILE_CSV); -> MQL5\Files\log.csv
- Shared Directory: FileOpen("log.csv", FILE_WRITE | FILE_CSV | FILE_COMMON); -> Common\Files\log.csv
- Subdirectories: You can specify relative subfolders such as "Data\\EURUSD.csv".
Reading CSV Records Row by Row
When reading a CSV file opened with FILE_CSV, each call to FileReadString(handle) reads the next token up to the delimiter or newline.
An end-of-file loop alone does not validate row width or data types. The example checks exactly six fields per row and logs strings, including the header. It targets the simple records it writes; it is not a general parser for quoted fields containing delimiters or embedded newlines.
Implementation details & mechanics
Core implementation pattern
Save this as a script in MQL5/Scripts. It writes a header and two explicitly synthetic quote records, then reads the file. Existing files are refused unless InpAllowOverwrite is enabled; enabling it replaces the entire file. The existence check is a convenience guard, not a concurrent-writer lock. For a real trade log, source data from confirmed transactions and define an append and recovery policy separately.
Error handling & safety rules
Every successful open must reach FileClose, including failure paths. Check FileWrite for zero and report the error; a partial file may remain after failure. FILE_READ | FILE_WRITE preserves an existing file, but appending also requires a successful FileSeek to SEEK_END. Write a header only when the file is empty. Flush or close before another reader consumes the file; this is not a transaction or crash-recovery guarantee.
MQL5 Code Implementation
//+------------------------------------------------------------------+
//| FileOpenCSVGuide.mq5 |
//| Copyright 2026, Pineify Guides Series |
//| https://pineify.app |
//+------------------------------------------------------------------+
#property copyright "Pineify Guides Series"
#property link "https://pineify.app/mql5/fileopen-csv-guide"
#property version "1.00"
#property script_show_inputs
//--- Input parameters
input string InpFileName = "pineify_csv_example.csv"; // CSV File Name
input bool InpAllowOverwrite = false; // Existing files are refused by default
input bool InpUseCommonFolder = true; // Use Shared Common\Files Folder
//+------------------------------------------------------------------+
//| Function: Write trade records to CSV |
//+------------------------------------------------------------------+
bool WriteTradeLogCSV(const string filename, bool useCommon)
{
if(!InpAllowOverwrite && FileIsExist(filename, useCommon ? FILE_COMMON : 0))
{
Print("Existing file refused: ", filename);
return false;
}
int flags = FILE_WRITE | FILE_CSV | FILE_ANSI;
if(useCommon)
flags |= FILE_COMMON;
// Open file for writing with comma ',' delimiter
int fileHandle = FileOpen(filename, flags, ',', CP_UTF8);
if(fileHandle == INVALID_HANDLE)
{
PrintFormat("Failed to open file %s for writing. Error: %d", filename, GetLastError());
return false;
}
// 1. Write Header Row
ResetLastError();
bool wrote = FileWrite(fileHandle, "Timestamp", "Symbol", "Action", "Lots", "Price", "Comment") > 0;
// 2. Write Data Rows
if(wrote) wrote = FileWrite(fileHandle,
TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS),
_Symbol,
"SAMPLE_BUY",
0.10,
SymbolInfoDouble(_Symbol, SYMBOL_ASK),
"Synthetic example only") > 0;
if(wrote) wrote = FileWrite(fileHandle,
TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS),
_Symbol,
"SAMPLE_QUOTE",
0.10,
SymbolInfoDouble(_Symbol, SYMBOL_BID),
"No order was sent") > 0;
int writeError = GetLastError();
// 3. Close File Handle even when a write fails
FileClose(fileHandle);
if(!wrote)
{
PrintFormat("CSV write failed: %d; a partial file may remain", writeError);
return false;
}
PrintFormat("Successfully wrote CSV records to %s", filename);
return true;
}
//+------------------------------------------------------------------+
//| Function: Read and parse CSV file records |
//+------------------------------------------------------------------+
bool ReadTradeLogCSV(const string filename, bool useCommon)
{
int flags = FILE_READ | FILE_CSV | FILE_ANSI;
if(useCommon)
flags |= FILE_COMMON;
int fileHandle = FileOpen(filename, flags, ',', CP_UTF8);
if(fileHandle == INVALID_HANDLE)
{
PrintFormat("Failed to open file %s for reading. Error: %d", filename, GetLastError());
return false;
}
Print("--- Reading CSV Data ---");
int lineNum = 0;
// Loop until end of file
while(!FileIsEnding(fileHandle))
{
string cols[6];
for(int i=0; i<6; ++i)
{
cols[i] = FileReadString(fileHandle);
if(i<5 && (FileIsLineEnding(fileHandle) || FileIsEnding(fileHandle)))
{
PrintFormat("Short CSV row %d", lineNum+1);
FileClose(fileHandle);
return false;
}
}
if(!FileIsLineEnding(fileHandle) && !FileIsEnding(fileHandle))
{
PrintFormat("Extra fields in CSV row %d", lineNum+1);
FileClose(fileHandle);
return false;
}
lineNum++;
PrintFormat("Row %d: [%s] | Symbol: %s | Action: %s | Lots: %s | Price: %s | Note: %s",
lineNum, cols[0], cols[1], cols[2], cols[3], cols[4], cols[5]);
}
FileClose(fileHandle);
PrintFormat("Finished reading %d rows from %s", lineNum, filename);
return true;
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
// Demo: Write sample records, then read them back
if(WriteTradeLogCSV(InpFileName, InpUseCommonFolder))
{
ReadTradeLogCSV(InpFileName, InpUseCommonFolder);
}
}
Copy this code into MetaEditor, save it in your MQL5 folder (Experts, Scripts, or Include), and compile with F7.
Generate custom MQL5 code with Pineify AI
Describe the trade execution, indicator calculations, risk management, or data processing logic you need. Pineify generates editable MQL5 source code. Review its logic, request a syntax check, and compile and test the final file in MetaEditor.
Frequently Asked Questions
Related MQL5 pages
Technical references
Risk and testing note
These educational examples require independent compilation and testing. A compile pass or an illustrative setting does not establish execution correctness or profitability. Any reported performance must be supported by reproducible data and test settings; past results do not predict future returns. Trading involves significant risk of loss. This content is not financial advice.