- Способы хранения информации: текстовый и двоичный
- Запись и чтение файлов в упрощенном режиме
- Открытие и закрытие файлов
- Управление дескрипторами файлов
- Выбор кодировки для текстового режима
- Запись и чтение массивов
- Запись и чтение структур (бинарные файлы)
- Запись и чтение переменных (бинарные файлы)
- Запись и чтение переменных (текстовые файлы)
- Управление позицией внутри файла
- Получение свойств файла
- Принудительная запись кэша на диск
- Удаление и проверка на существование файла
- Копирование и перемещение файлов
- Поиск файлов и папок
- Работа с папками
- Диалог выбора файла или папки
Получение свойств файла
В процессе работы с файлами помимо непосредственно записи и чтения данных часто возникает необходимость проанализировать их свойства. Одно из основных свойств — размер файла — можно получить с помощью функции FileSize. Но есть и еще несколько характеристик, которые можно запросить с помощью FileGetInteger.
Обратите внимание, что функция FileSize требует наличия дескриптора открытого файла. А у функции FileGetInteger есть часть свойств, которые можно узнать по имени файла, без необходимости его предварительно открывать (в том числе и размер).
ulong FileSize(int handle)
Функция возвращает размер открытого файла по его дескриптору. В случае ошибки результат равен 0, что является допустимым размером и при штатном выполнении функции, поэтому анализ потенциальных ошибок требуется всегда проводить с помощью _LastError (или GetLastError).
Размер файла можно также получить путем перемещения указателя в конец файла FileSeek(handle, 0, SEEK_END) и вызова FileTell(handle) — обе функции описаны в предыдущем разделе.
long FileGetInteger(int handle, ENUM_FILE_PROPERTY_INTEGER property)
long FileGetInteger(const string filename, ENUM_FILE_PROPERTY_INTEGER property, bool common = false)
Функция имеет 2 варианта: для работы через дескриптор открытого файла и по имени файла (в том числе закрытого).
Функция возвращает одно из свойств файла, указанное в параметре property, причем перечень допустимых свойств отличается для каждого из вариантов (см. ниже). Несмотря на то, что тип значения — long, он может содержать, в зависимости от запрошенного свойства, не только целое число, но и datetime или bool: выполните необходимое приведение типа явным образом.
При запросе свойства по имени файла можно дополнительно уточнить с помощью параметра common, в какой папке следует искать файл: текущего терминала MQL5/Files (false, по умолчанию) или общей Users/<пользователь>...MetaQuotes/Terminal/Common/Files (true). Если MQL-программа выполняется в тестере, рабочий каталог расположен внутри папки агента тестирования (Tester/<агент>/MQL5/Files), см. вводную часть главы Работа с файлами.
В следующей таблице перечислены все элементы ENUM_FILE_PROPERTY_INTEGER.
Свойство |
Описание |
---|---|
FILE_EXISTS * |
Проверка на существование (аналог FileIsExist) |
FILE_CREATE_DATE * |
Дата создания |
FILE_MODIFY_DATE * |
Дата последнего изменения |
FILE_ACCESS_DATE * |
Дата последнего доступа |
FILE_SIZE * |
Размер файла в байтах (аналог FileSize) |
FILE_POSITION |
Позиция указателя в файле (аналог FileTell) |
FILE_END |
Признак позиции в конце файла (аналог FileIsEnding) |
FILE_LINE_END |
Признак позиции в конце строки (аналог FileIsLineEnding) |
FILE_IS_COMMON |
Файл открыт в общей папке терминалов (FILE_COMMON) |
FILE_IS_TEXT |
Файл открыт как текстовый (FILE_TXT) |
FILE_IS_BINARY |
Файл открыт как бинарный (FILE_BIN) |
FILE_IS_CSV |
Файл открыт как CSV (FILE_CSV) |
FILE_IS_ANSI |
Файл открыт как ANSI (FILE_ANSI) |
FILE_IS_READABLE |
Файл открыт на чтение (FILE_READ) |
FILE_IS_WRITABLE |
Файл открыт на запись (FILE_WRITE) |
Свойства, разрешенные для использования по имени файла, помечены звездочкой. При попытке получения других свойств второй вариант функции вернет ошибку 4003 (INVALID_PARAMETER).
Часть свойств может меняться в процессе работы с открытым файлом: FILE_MODIFY_DATE, FILE_ACCESS_DATE, FILE_SIZE, FILE_POSITION, FILE_END, FILE_LINE_END (только для текстовых файлов).
В случае ошибки результат вызова равен -1.
Второй вариант функции позволяет проверить, является ли указанное имя именем файла или каталога. Если при получении свойств по имени будет указан каталог, то функция выставит специальный код внутренней ошибки 5018 (ERR_MQL_FILE_IS_DIRECTORY), при этом возвращаемое значение будет корректным.
Функции данного раздела протестируем в скрипте FileProperties.mq5. Он будет работать с файлом с предопределенным именем.
const string fileprop = "MQL5Book/fileprop"; |
В начале OnStart попробуем запросить размер по ошибочному дескриптору (он не был получен через вызов FileOpen). После FileSize потребуется проверка переменной _LastError, а FileGetInteger сразу возвращает специальное значение — индикатор ошибки (-1).
void OnStart()
|
Далее мы создаем новый или открываем существующий файл и обнуляем его, а затем записываем тестовый текст.
handle = PRTF(FileOpen(fileprop, FILE_TXT | FILE_WRITE | FILE_ANSI)); // 1
|
Выборочно запрашиваем некоторые из свойств.
PRTF(FileGetInteger(fileprop, FILE_SIZE)); // 0, еще не записан на диск
|
Информация о длине файла по его дескриптору учитывает текущий буфер кэширования, а по имени файла актуальная длина станет доступна только после закрытия файла или если вызвать функцию FileFlush (см. раздел Принудительная запись кэша на диск).
Даты и время функция возвращает как количество секунд стандартной эпохи с 1 января 1970 года, что соответствует типу datetime и может быть приведено к нему.
Запрос флагов открытия файла (его режима) успешно проходит для варианта функции с дескриптором, в частности, мы получили ответ, что файл является текстовым и не двоичным. Однако следующий аналогичный запрос по имени файла завершится ошибкой, так как свойство поддерживается только при передаче валидного дескриптора. Это происходит несмотря на то, что имя указывает на тот же файл, который мы открыли.
PRTF(FileGetInteger(fileprop, FILE_IS_TEXT)); // -1 / INVALID_PARAMETER(4003) |
Выждем 1 секунду, закроем файл и снова проверим дату модификации (на этот раз по имени, т.к. дескриптор уже не действует).
Sleep(1000);
|
Здесь наглядно видно, что время увеличилось на 1.
Наконец, убедимся, что свойства доступны и для директорий (каталогов).
PRTF((datetime)FileGetInteger("MQL5Book", FILE_CREATE_DATE));
|
Поскольку все примеры книги расположены в папке "MQL5Book", она должна уже существовать. Однако актуальное время создания у вас будет отличаться. Код ошибки FILE_IS_DIRECTORY в данном случае для нас выводит макрос PRTF. В рабочей программе вызов функции следует делать без макроса, а код затем прочитать в _LastError.