Работа с файлами

Редко какая программа обходится без ввода-вывода данных. Мы уже знаем, что MQL-программы могут получать настройки через входные переменные и выводить информацию в журнал — последним мы пользовались практически во всех тестовых скриптах. Но этого недостаточно в большинстве случаев.

Например, довольно часть настройки программы включают объемы данных, которые нельзя уместить во входных параметрах. Или программу необходимо интегрировать с некими внешними аналитическими средствами, то есть выгружать рыночную информацию в стандартном или специализированном формате, обрабатывать и затем загружать в терминал в новом виде, в частности, как торговые сигналы, набор весов нейронной сети или коэффициенты дерева решений. Да и журнал бывает удобно вести для MQL-программы отдельный, собственный.

Наиболее универсальные возможности для подобных задач предоставляет файловая подсистема. И MQL5 API содержит широкий спектр функций по работе с файлами, включая их создание, удаление, поиск, запись и считывание. Всё это мы изучим в данной главе.

Все операции с файлами в MQL5 ограничены особой областью на диске, которая называется "песочницей". Это сделано из соображений безопасности, чтобы ни одна MQL-программа не могла использоваться в злонамеренных целях и навредить вашему компьютеру и операционной системе.

Продвинутые пользователи имеют возможность обойти это ограничение с помощью специальных мер, о которых мы расскажем чуть ниже, но делать это следует только в исключительных случаях, соблюдая меры предосторожности и принимая на себя всю ответственность.

У каждого экземпляра терминала, установленного на компьютере, корневой каталог "песочницы" располагается по пути: <папка_данных_терминала>/MQL5/Files/. Из редактора MetaEditor легко найти папку данных с помощью команды Файл -> Открыть каталог данных. При наличии достаточных прав доступа на компьютере этот каталог, как правило, совпадает с тем местом, куда установлен терминал. Если прав недостаточно, путь будет иметь вид:

X:/Users/<user_name>/AppData/Roaming/MetaQuotes/Terminal/<instance_id>/MQL5/Files/

Здесь X — литера диска, где установлена система, <user_name> — логин пользователя Windows, <instance_id> — уникальный идентификатор экземпляра терминала. Папка Users также имеет алиас "Documents and Settings".

Обратите внимание, что если подключение к компьютеру осуществляется удаленно через RDP (Remote Desktop Protocol), то в любом случае используется каталог Roaming и его подкаталоги, даже если у вас есть административные права.

Напомним, что папка MQL5 в каталоге данных — это то место, где хранятся все MQL-программы: как их исходные коды, так и скомпилированные ex5-файлы. Каждый тип MQL-программ — индикаторы, эксперты, скрипты и прочие — имеет в папке MQL5 выделенную вложенную папку. Таким образом, папка Files для рабочих файлов находится с ними по соседству.

Помимо этой "персональной" "песочницы" каждой копии терминала на компьютере имеется общая, разделяемая "песочница" для всех терминалов: через неё они могут "общаться". Путь к ней "пролегает" через домашнюю папку пользователя Windows и может отличаться в зависимости от версии операционной системы. Например, в стандартных установках Windows 7, 8, 10 он имеет вид:

X:/Users/<user_name>/AppData/Roaming/MetaQuotes/Terminal/Common/Files/

Редактор MetaTrader и в данном случае облегчает поиск папки: достаточно выполнить команду Файл -> Открыть общую папку данных, и вы окажетесь внутри папки Common.

Следует напомнить, что некоторые типы MQL-программ (эксперты и индикаторы) способны выполняться не только в терминале, но и тестере. При работе в нем общая "песочница" остается доступной, а вместо "песочницы" отдельного экземпляра используется папка внутри агента тестирования. Как правило, она имеет вид:

X:/<путь_к_терминалу>/Tester/Agent-IP-port/MQL5/Files/

Из самой MQL-программы это обстоятельство незаметно, то есть все файловые функции работают совершенно одинаково, однако с точки зрения пользователя может сложиться впечатление, что существует какая-то проблема. Например, если программа сохранит результаты своей работы в файл, тот будет удален в папке агента тестера после окончания прогона (как будто файл и не создавался). Такое поведение задумано с целью предотвратить утечку потенциально ценных данных одной программы в другую программу, которая может тестироваться на том же агенте спустя какое-то время (тем более что агенты могут быть в общем доступе). Для передачи файлов на агенты и возврата результатов с агентов в терминал предусмотрены другие технологии, о которых мы поговорим в пятой части книги.

Для того чтобы обойти ограничение на "песочницу", можно воспользоваться способностью Windows назначать символические ссылки на объекты файловой системы. В нашем случае, для перенаправления доступа к папкам на локальном компьютере лучше всего подходят так называемые соединения (junction). Они создаются с помощью следующей команды (имеется в виду командная строка Windows):

mklink /J new_name existing_target

Параметр new_name — это имя новой виртуальной "папки", которая будет указывать на реальную папку existing_target.

Для создания соединений к внешним папками вне "песочницы" рекомендуется завести внутри MQL5/Files выделенную папку, например, Links. Затем зайдя в неё можно выполнить вышеуказанную команду, выбрав new_name и подставив реальный путь вне "песочницы" в качестве existing_target. Например, следующая команда создаст в папке Links новую ссылку с именем Settings, которая обеспечит обращение к папке MQL5/Presets:

mklink /J Settings "..\..\Presets\"

Относительный путь "..\..\" предполагает, что команда выполняется в указанной папке MQL5/Files/Links. Сочетание двух точек ".." обозначает переход из текущей папки в родительскую. Указанная дважды, эта комбинация предписывает два раза подняться наверх по иерархии пути. В результате целевая папка (existing_target) сформируется как MQL5/Presets. Но в параметре existing_target можно задавать и абсолютный путь.

Удалить символические ссылки можно как обычные файлы (но, разумеется, следует предварительно убедиться, что удаляется именно папка со значком стрелочки в её левом нижнем углу, т.е. ссылка, а не оригинальная папка). Рекомендуется делать это сразу же после того, как необходимость в прорыве за границу "песочницы" отпала. Дело в том, что созданные виртуальные папки становятся доступны всем MQL-программам, а не только вашей, и не известно, как дополнительную свободу могу использовать чужие программы.

Во многих разделах главы речь пойдет об именах файлов. Они выступают в роли идентификаторов элементов файловой системы и для них существуют похожие правила, в том числе и кое-какие ограничения.

Напомним, что имя файла не может содержать некоторые символы, которые играют особые роли в файловой системе ('<', '>', '/', '\\', '"', ':', '|', '*', '?'), а также любые символы с кодами от 0 до 31 включительно.

Также в операционной системе зарезервированы для специального применения и не могут использоваться следующие имена файлов: CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9.

Следует учесть, что файловая система Windows не "видит" принципиальной разницы между буквами в разных регистрах, поэтому имена вроде "Name", "NAME", "name" ссылаются на один и тот же элемент.

В качестве символа разделителя между составными частями пути (вложенными папками и файлом) Windows позволяет использовать как обратную косую черту '\\', так и прямую '/'. Однако обратный слэш требуется экранировать (то есть, фактически писать его дважды) в строках MQL5, потому что сам символ '\' является специальным: с помощью него строятся последовательности управляющих символов, такие как '\r', '\n', '\t' и другие (см. раздел Символьные типы). Например, следующие пути эквивалентны: "MQL5Book/file.txt" и "MQL5Book\\file.txt".

Символ точки '.' служит разделителем между именем и расширением. Если элемент файловой системы имеет несколько точек в своем идентификаторе, то расширением считается фрагмент справа от самой правой точки, а все, что слева от неё, является именем. Название (перед точкой) или расширение (после точки) может быть пустым. Например, вот имя файла без расширения — "text", а вот файл без имени (только с расширением) — ".txt".

Общая длина пути и имени файла в Windows имеет ограничения. При этом для управления файлами в MQL5 следует учитывать, что к их пути и имени будет спереди добавлен путь к самой "песочнице", то есть на названия файловых объектов в вызовах MQL-функций будет отведено еще меньше места. По умолчанию, общее ограничение длины составляет системную константу MAX_PATH, равную 260. Начиная с Windows 10 (сборки 1607) вы можете увеличить этот предел до 32767. Для этого необходимо сохранить следующий текст в reg-файл и запустить его, добавив в Реестр Windows.
 
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem]
"LongPathsEnabled"=dword:00000001
 
Для других версий Windows можно воспользоваться "обходными маневрами" из командной строки. В частности, сократить путь можно с помощью рассмотренных выше соединений (создав виртуальную папку с кратким путем). Также можно применить команду оболочки — subst, например, subst z: с:\very\long\path (см. подробности в справке Windows).