- Способы хранения информации: текстовый и двоичный
- Запись и чтение файлов в упрощенном режиме
- Открытие и закрытие файлов
- Управление дескрипторами файлов
- Выбор кодировки для текстового режима
- Запись и чтение массивов
- Запись и чтение структур (бинарные файлы)
- Запись и чтение переменных (бинарные файлы)
- Запись и чтение переменных (текстовые файлы)
- Управление позицией внутри файла
- Получение свойств файла
- Принудительная запись кэша на диск
- Удаление и проверка на существование файла
- Копирование и перемещение файлов
- Поиск файлов и папок
- Работа с папками
- Диалог выбора файла или папки
Диалог выбора файла или папки
В группе функций по работе с файлами и папками есть одна, позволяющая интерактивно запросить имя файла или папки, а также группу файлов у пользователя, чтобы передать эту информацию в MQL-программу. Вызов данной функций — FileSelectDialog — приводит к появлению в терминале стандартного окна выбора файлов и папок системы Windows.
Поскольку диалог прерывает выполнение MQL-программы до момента его закрытия, вызов функции разрешен только в двух типах MQL-программ, которые исполняются в отдельных потоках: экспертах и скриптах (см. раздел о типах MQL-программ). Пользоваться данной функцией запрещено в индикаторах и сервисах: первые исполняются в интерфейсном потоке терминала (и их остановка заморозила бы обновление графиков соответствующих инструментов), а вторые исполняются в фоновом режиме и не могут обращаться к пользовательскому интерфейсу.
Все элементы файловой системы, с которыми работает функция, находятся внутри "песочницы", то есть в каталоге текущей копии терминала или агента тестирования (если программа выполняется в тестере), в подпапке MQL5/Files.
При наличии флага FSD_COMMON_FOLDER в параметре flags (см. далее) используется общая "песочница" всех терминалов Users/<пользователь>...MetaQuotes/Terminal/Common/Files.
Внешний вид диалога зависит от операционной системы Windows. Ниже показан один из возможных вариантов интерфейса.
Диалог выбора файлов и папок Windows
int FileSelectDialog(const string caption, const string initDir, const string filter,
uint flags, string &filenames[], const string defaultName)
Функция выводит стандартный диалог Windows для открытия или создания файла, или выбора папки. В параметре caption задается заголовок диалога: при значении NULL используется стандартный заголовок — "Открыть" для чтения или "Сохранить как" для записи файла, или же "Выбор папки", в зависимости от флагов в параметре flags.
Параметр initDir позволяет задать начальную папку, для которой откроется диалог. При значении NULL будет показано содержимое папки MQL5/Files. Эта же папка используется, если в initDir указан несуществующий путь.
С помощью параметра filter можно ограничить набор расширений файлов, которые будут показаны в диалоговом окне. Файлы других форматов будут скрыты. Значение NULL означает отсутствие ограничений.
Формат строки filter следующий:
"<описание 1>|<расширение 1>|<описание 2>|<расширение 2>..." |
В качестве описания допустима любая строка. В качестве расширения можно написать любой фильтр с подстановочными символами '*' и '?', которые мы рассматривали в разделе Поиск файлов и папок. Символ '|' является разделителем.
Поскольку соседние описание и расширение образуют логически связанную пару, общее количество элементов в строке должно быть четным, а количество разделителей — нечетным.
Каждое сочетание описания и расширения генерирует отдельный вариант выбора в выпадающем списке диалога. Описание показывается пользователю, а расширение используется для фильтрации.
Например, "Text documents (*.txt)|*.txt|All files (*.*)|*.*", при этом первое расширение "Text documents (*.txt)|*.txt" будет выбрано как тип файла по умолчанию.
В параметре flags можно указать с помощью оператора '|' битовую маску, задающую режимы работы. Для неё определены следующие константы:
- FSD_WRITE_FILE — режим для записи файлов ("Сохранить как"); при отсутствии данного флага по умолчанию используется режим чтения ("Открыть"); при наличии данного флага всегда разрешен ввод произвольного нового имени, независимо от флага FSD_FILE_MUST_EXIST;
- FSD_SELECT_FOLDER — режим выбора папки (только одной и только существующей); при данном флаге все прочие флаги кроме FSD_COMMON_FOLDER игнорируются или вызывают ошибку; запросить явным образом создание папки нельзя, но в диалоге есть возможность создать папку интерактивно и тут же её выбрать;
- FSD_ALLOW_MULTISELECT — разрешение выбирать несколько файлов в режиме чтения; этот флаг игнорируется, если указан FSD_WRITE_FILE или FSD_SELECT_FOLDER;
- FSD_FILE_MUST_EXIST — выбранные файлы должны существовать; если пользователь попытается указать произвольное имя, диалог выведет предупреждение и останется открытым; данный флаг игнорируется, если указан режим FSD_WRITE_FILE;
- FSD_COMMON_FOLDER — диалог открывается для общей "песочницы" всех клиентских терминалов.
Функция заполнят массив строк filenames именами выбранных файлов или папки. Если массив динамический, его размер изменяется под фактическое количество данных, в частности, расширяется или наоборот урезается вплоть до 0, если ничего не было выбрано. Если массив фиксированный, он должен быть достаточного размера, чтобы принять ожидаемые данные. В противном случае возникнет ошибка 4007 (ARRAY_RESIZE_ERROR).
Параметр defaultName указывает имя файла/папки по умолчанию, которое будет подставлено в соответствующее поле ввода сразу после открытия диалога. Если параметр равен NULL, поле будет изначально пустым.
Если параметр defaultName задан, то во время невизуального тестирования MQL-программы вызов FileSelectDialog вернёт 1, а само значение defaultName будет скопировано в массив filenames.
Функция возвращает количество выбранных элементов (0, если пользователь ничего не выбрал) или -1 в случае ошибки.
Рассмотрим примеры работы функции в скрипте FileSelect.mq5. В функции OnStart будем последовательно вызывать FileSelectDialog с разными настройками. Пока пользователь выбирает что-то (не нажимает кнопку "Отмена" в диалоге), тест продолжается вплоть до последнего шага (даже если функция выполнилась с кодом ошибки).
void OnStart()
|
Сперва запросим у пользователя один файл из папки "MQL5Book". Можно выбрать существующий файл или ввести новое имя (потому что нет флага FSD_FILE_MUST_EXIST).
Print("Open a file");
|
В предположении, что в папке присутствуют как минимум 5 файлов из поставки книги, здесь выбран один из них.
Затем сделаем аналогичный запрос в режиме "для записи" (с флагом FSD_WRITE_FILE).
Print("Save as a file");
|
Здесь пользователь также сможет выбрать как существующий файл, так и ввести новое имя. Проверку на то, что пользователь собирается перезаписать существующий файл, должен сделать программист (диалог предупреждений не выдает).
Теперь проверим выбор нескольких файлов (FSD_ALLOW_MULTISELECT) в динамический массив.
if(PRTF(FileSelectDialog(NULL, "MQL5book", NULL,
|
Наличие флага FSD_FILE_MUST_EXIST означает, что диалог выведет предупреждение и останется открытым, если попытаться ввести новое имя.
Если попробовать похожим образом выбрать более 1 файла в массив фиксированного размера, мы получим ошибку.
Print("Open multiple files (fixed, choose more than 1 file for error)");
|
Наконец, протестируем работу с папками (FSD_SELECT_FOLDER).
Print("Select a folder");
|
В данном случае в качестве стартового пути указана несуществующая вложенная папка "nonexistent", поэтому диалог откроется в корне "песочницы" — MQL5/Files. Там мы выбрали "MQL5book".
Если скомбинировать некорректное сочетание флагов, получим еще одну ошибку.
if(PRTF(FileSelectDialog(NULL, "MQL5book", NULL,
|
Из-за ошибки функция не стала модифицировать переданный массив, и в нем остался прежний элемент "MQL5Book".
В данном тесте мы намеренно проверяли результаты только на 0, чтобы продемонстрировать все варианты вне зависимости от наличия ошибок. В реальной программе проверяйте результат функции с учетом ошибок, т.е. с условиями на три исхода: выбор сделан (>0), выбор не сделан (==0) и ошибка (<0).