Làm việc với thư mục
Thật khó để tưởng tượng một hệ thống tệp mà không có khả năng tổ chức thông tin được lưu trữ thông qua một hệ thống phân cấp thư mục tùy ý — các vùng chứa cho các tập hợp tệp có liên quan logic. Ở cấp độ MQL5, tính năng này cũng được hỗ trợ. Nếu cần, chúng ta có thể tạo, dọn dẹp và xóa thư mục bằng các hàm tích hợp sẵn FolderCreate
, FolderClean
và FolderDelete
.
Trước đây, chúng ta đã thấy một cách để tạo thư mục, và có lẽ không chỉ một, mà cả hệ thống phân cấp thư mục con cần thiết cùng một lúc. Để làm điều này, khi tạo (mở) một tệp bằng FileOpen
, hoặc khi sao chép tệp (FileCopy
, FileMove
), bạn nên chỉ định không chỉ tên mà còn kèm theo đường dẫn cần thiết trước đó. Ví dụ:
FileCopy("MQL5Book/unicode1.txt", 0, "ABC/DEF/code.txt", 0);
Câu lệnh này sẽ tạo thư mục ABC
trong sandbox, thư mục DEF
bên trong nó, và sao chép tệp vào đó dưới một tên mới (tệp nguồn phải tồn tại).
Nếu bạn không muốn tạo tệp nguồn trước, bạn có thể tạo một tệp giả lập ngay lập tức:
uchar dummy[];
FileSave("ABC/DEF/empty", dummy);
2
Ở đây, chúng ta sẽ nhận được cùng hệ thống phân cấp thư mục như trong ví dụ trước nhưng với một tệp empty
có kích thước bằng 0.
Với các phương pháp như vậy, việc tạo thư mục trở thành một loại sản phẩm phụ của việc làm việc với tệp. Tuy nhiên, đôi khi cần thao tác với thư mục như các thực thể độc lập và không có tác dụng phụ, đặc biệt là chỉ tạo một thư mục trống. Điều này được cung cấp bởi hàm FolderCreate
.
bool FolderCreate(const string folder, int flag = 0)
Hàm này tạo một thư mục có tên folder
, có thể bao gồm đường dẫn (nhiều tên thư mục cấp cao). Trong cả hai trường hợp, một thư mục đơn hoặc hệ thống phân cấp thư mục được tạo trong sandbox được xác định bởi tham số flag
. Theo mặc định, khi flag
là 0, thư mục làm việc cục bộ MQL5/Files
của terminal hoặc tester agent (nếu chương trình chạy trong tester) được sử dụng. Nếu flag
bằng FILE_COMMON
, thư mục chung của tất cả các terminal được sử dụng.
Hàm trả về true
khi thành công hoặc nếu thư mục đã tồn tại. Trong trường hợp có lỗi, kết quả là false
.
bool FolderClean(const string folder, int flag = 0)
Hàm này xóa tất cả tệp và thư mục ở bất kỳ cấp độ lồng nhau nào (cùng với toàn bộ nội dung) trong thư mục folder
được chỉ định. Tham số flag
xác định sandbox (cục bộ hoặc toàn cục) nơi hành động diễn ra.
Sử dụng tính năng này một cách cẩn thận, vì tất cả tệp và thư mục con (cùng với tệp của chúng) sẽ bị xóa vĩnh viễn.
bool FolderDelete(const string folder, int flag = 0)
Hàm này xóa thư mục được chỉ định (folder
). Trước khi gọi hàm, thư mục phải trống, nếu không nó không thể bị xóa.
Các kỹ thuật làm việc với ba hàm này được thể hiện trong script FileFolder.mq5
. Bạn có thể thực thi script này ở chế độ gỡ lỗi từng bước (từng câu lệnh) và quan sát trong trình quản lý tệp cách các thư mục và tệp xuất hiện và biến mất. Tuy nhiên, lưu ý rằng trước khi thực hiện câu lệnh tiếp theo, bạn nên sử dụng trình quản lý tệp để thoát khỏi các thư mục đã tạo lên đến cấp MQL5Book
, vì nếu không, các thư mục có thể bị trình quản lý tệp chiếm dụng, và điều này sẽ làm gián đoạn script.
Đầu tiên, chúng ta tạo một số thư mục con như một sản phẩm phụ của việc ghi một tệp giả lập trống vào chúng.
void OnStart()
{
const string filename = "MQL5Book/ABC/DEF/dummy";
uchar dummy[];
PRTF(FileSave(filename, dummy)); // true
2
3
4
5
Tiếp theo, chúng ta tạo một thư mục khác ở cấp độ lồng thấp nhất bằng FolderCreate
: Lần này thư mục xuất hiện độc lập, không có tệp hỗ trợ.
PRTF(FolderCreate("MQL5Book/ABC/GHI")); // true
Nếu bạn cố gắng xóa thư mục DEF
, nó sẽ thất bại vì thư mục không trống (có một tệp trong đó).
PRTF(FolderDelete("MQL5Book/ABC/DEF")); // false / CANNOT_DELETE_DIRECTORY(5024)
Để xóa nó, bạn phải dọn dẹp nó trước, và cách dễ nhất là sử dụng FolderClean
. Nhưng chúng ta sẽ thử mô phỏng một tình huống phổ biến khi một số tệp trong các thư mục đang được dọn dẹp có thể bị khóa bởi các chương trình MQL khác, ứng dụng bên ngoài hoặc chính terminal. Hãy mở tệp để đọc và gọi FolderClean
.
int handle = PRTF(FileOpen(filename, FILE_READ)); // 1
PRTF(FolderClean("MQL5Book/ABC")); // false / CANNOT_CLEAN_DIRECTORY(5025)
2
Hàm trả về false
và hiển thị mã lỗi 5025 (CANNOT_CLEAN_DIRECTORY
). Sau khi chúng ta đóng tệp, việc dọn dẹp và xóa toàn bộ hệ thống phân cấp thư mục sẽ thành công.
FileClose(handle);
PRTF(FolderClean("MQL5Book/ABC")); // true
PRTF(FolderDelete("MQL5Book/ABC")); // true
}
2
3
4
Các khóa tiềm ẩn có khả năng xảy ra nhiều hơn khi sử dụng thư mục terminal chung, nơi cùng một tệp hoặc thư mục có thể bị "yêu cầu" bởi các phiên chương trình khác nhau. Nhưng ngay cả trong sandbox cục bộ, bạn không nên quên các xung đột có thể xảy ra (ví dụ, nếu một tệp csv được mở trong Excel). Hãy triển khai chẩn đoán chi tiết và xuất lỗi cho các phần mã làm việc với thư mục, để người dùng có thể nhận ra và khắc phục vấn đề.