Trabajar con carpetas

Es difícil imaginar un sistema de archivos sin la capacidad de estructurar la información almacenada mediante una jerarquía arbitraria de directorios: contenedores de conjuntos de archivos relacionados lógicamente. En el nivel MQL5, esta función también se admite. Si es necesario, podemos crear, limpiar y eliminar carpetas utilizando las funciones integradas FolderCreate, FolderClean, y FolderDelete.

Anteriormente vimos ya una forma de crear una carpeta, y, tal vez, no una, sino toda la jerarquía necesaria de subcarpetas a la vez. Para ello, al crear (abrir) un archivo mediante FileOpen, o al copiarlo (FileCopy, FileMove), debe especificar no sólo un nombre, sino encabezarlo con la ruta requerida. Por ejemplo:

   FileCopy("MQL5Book/unicode1.txt"0"ABC/DEF/code.txt"0);

Esta sentencia creará la carpeta «ABC» en la «sandbox», la carpeta «DEF» en ella, y copiará allí el archivo con un nuevo nombre (el archivo fuente debe existir).

Si no desea crear un archivo fuente de antemano, puede crear un archivo ficticio sobre la marcha:

   uchar dummy[];
   FileSave("ABC/DEF/empty"dummy);

Aquí obtendremos la misma jerarquía de carpetas que en el ejemplo anterior pero con un archivo «vacío» de tamaño cero.

Con estos enfoques, la creación de carpetas se convierte en una especie de subproducto del trabajo con archivos. Sin embargo, a veces es necesario operar con carpetas como entidades independientes y sin efectos secundarios; en concreto, basta con crear una carpeta vacía. Esto lo ofrece la función FolderCreate.

bool FolderCreate(const string folder, int flag = 0)

La función crea una carpeta llamada folder, que puede incluir una ruta (varios nombres de carpetas de nivel superior). En ambos casos se crea una única carpeta o jerarquía de carpetas en la «sandbox» definida por el parámetro flag. De manera predeterminada, cuando flag es 0, se utiliza la carpeta de trabajo local MQL5/Files del terminal o del agente del probador (si el programa se está ejecutando en el probador). Si flag es igual a FILE_COMMON, se utiliza la carpeta compartida de todos los terminales.

La función devuelve true en caso de éxito, o si la carpeta ya existe. En caso de error, el resultado es false.

bool FolderClean(const string folder, int flag = 0)

La función elimina todos los archivos y carpetas de cualquier nivel de anidamiento (junto con todo el contenido) del directorio folder especificado. El parámetro flag especifica la «sandbox» (local o global) en la que tiene lugar la acción.

Utilice esta función con precaución, ya que todos los archivos y subcarpetas (con sus archivos) se eliminan permanentemente.

bool FolderDelete(const string folder, int flag = 0)

La función borra la carpeta especificada (folder). Antes de llamar a la función, la carpeta debe estar vacía; de lo contrario no se podrá eliminar.

Las técnicas para trabajar con estas tres funciones se muestran en el script FileFolder.mq5. Puedes ejecutar este script en el modo de depuración paso a paso (sentencia por sentencia) y observar en el administrador de archivos cómo aparecen y desaparecen carpetas y archivos. Sin embargo, tenga en cuenta que antes de ejecutar la siguiente instrucción, debe usar el gestor de archivos para salir de las carpetas creadas hasta el nivel «MQL5Book», ya que de lo contrario las carpetas pueden estar ocupadas por el administrador de archivos, y esto interrumpirá el script.

Primero creamos varias subcarpetas como subproducto de escribir en ellas un archivo ficticio vacío.

void OnStart()
{
   const string filename = "MQL5Book/ABC/DEF/dummy";
   uchar dummy[];
   PRTF(FileSave(filenamedummy)); // true

A continuación, creamos otra carpeta en el nivel de anidamiento inferior con FolderCreate: Esta vez la carpeta aparece sola, sin el archivo de ayuda.

   PRTF(FolderCreate("MQL5Book/ABC/GHI")); // true

Si intenta eliminar la carpeta «DEF» fallará porque no está vacía (hay un archivo allí).

   PRTF(FolderDelete("MQL5Book/ABC/DEF")); // false / CANNOT_DELETE_DIRECTORY(5024)

Para eliminarlo, primero debe borrarlo, y la forma más fácil de hacerlo es con FolderClean. No obstante, intentaremos simular una situación común cuando algunos archivos de las carpetas que se están limpiando pueden estar bloqueados por otros programas MQL, aplicaciones externas o el propio terminal. Vamos a abrir el archivo para leerlo y a llamar a FolderClean.

   int handle = PRTF(FileOpen(filenameFILE_READ)); // 1
   PRTF(FolderClean("MQL5Book/ABC")); // false / CANNOT_CLEAN_DIRECTORY(5025)

La función devuelve false y expone el código de error 5025 (CANNOT_CLEAN_DIRECTORY). Después de cerrar el archivo, la limpieza y eliminación de toda la jerarquía de carpetas se realiza correctamente.

   FileClose(handle);
   PRTF(FolderClean("MQL5Book/ABC")); // true
   PRTF(FolderDelete("MQL5Book/ABC")); // true
}

Los posibles bloqueos son más probables cuando se utiliza un directorio de terminal compartido, donde el mismo archivo o carpeta puede ser «reclamado» por diferentes instancias del programa. Pero incluso en una «sandbox» local no hay que olvidarse de posibles conflictos (por ejemplo, si se abre un archivo csv en Excel). Implemente diagnósticos detallados y salida de errores para las partes de código que trabajan con carpetas, de forma que el usuario pueda darse cuenta y solucionar el problema.