Sao chép và di chuyển tệp
Các thao tác chính trên tệp ở cấp độ hệ thống tệp là sao chép và di chuyển. Để thực hiện các mục đích này, MQL5 cung cấp hai hàm với nguyên mẫu giống nhau.
bool FileCopy(const string source, int flag, const string destination, int mode)
Hàm này sao chép tệp source
sang tệp destination
. Cả hai tham số được đề cập có thể chỉ chứa tên tệp hoặc tên cùng với đường dẫn tiền tố (các cấp thư mục) trong các sandbox của MQL5. Tham số flag
và mode
xác định thư mục làm việc nào sẽ tìm tệp nguồn và thư mục làm việc nào là đích: 0 có nghĩa là thư mục của phiên terminal hiện tại (hoặc tester agent nếu chương trình đang chạy trong tester), còn giá trị FILE_COMMON
có nghĩa là thư mục chung cho tất cả các terminal.
Ngoài ra, trong tham số mode
, bạn có thể tùy chọn chỉ định hằng số FILE_REWRITE
(nếu cần kết hợp FILE_REWRITE
và FILE_COMMON
, điều này được thực hiện bằng cách sử dụng toán tử bitwise OR (|)). Nếu không có FILE_REWRITE
, việc sao chép đè lên tệp hiện có bị cấm. Nói cách khác, nếu tệp với đường dẫn và tên được chỉ định trong tham số destination
đã tồn tại, bạn phải xác nhận ý định ghi đè bằng cách đặt FILE_REWRITE
. Nếu không làm điều này, lời gọi hàm sẽ thất bại.
Hàm trả về true
khi hoàn thành thành công hoặc false
trong trường hợp có lỗi.
Việc sao chép có thể thất bại nếu tệp nguồn hoặc tệp đích đang bị chiếm dụng (được mở) bởi một tiến trình khác.
Khi sao chép tệp, siêu dữ liệu của chúng (thời gian tạo, quyền truy cập, luồng dữ liệu thay thế) thường được lưu lại. Nếu bạn cần thực hiện sao chép "thuần túy" chỉ với dữ liệu của chính tệp, bạn có thể sử dụng các lời gọi liên tiếp
FileLoad
vàFileSave
, xem Ghi và đọc tệp ở chế độ đơn giản hóa.
bool FileMove(const string source, int flag, const string destination, int mode)
Hàm này di chuyển hoặc đổi tên một tệp. Đường dẫn và tên nguồn được chỉ định trong tham số source
, còn đường dẫn và tên đích được chỉ định trong destination
.
Danh sách các tham số và nguyên tắc hoạt động của chúng giống với hàm FileCopy
. Nói một cách đơn giản, FileMove
thực hiện công việc tương tự như FileCopy
, nhưng nó còn xóa tệp gốc sau khi sao chép thành công.
Hãy tìm hiểu cách làm việc với các hàm này trong thực tế bằng script FileCopy.mq5
. Script này có hai biến chứa tên tệp. Cả hai tệp đều không tồn tại khi script được chạy.
const string source = "MQL5Book/source";
const string destination = "MQL5Book/destination";
2
Trong OnStart
, chúng ta thực hiện một chuỗi hành động theo kịch bản đơn giản. Đầu tiên, chúng ta cố gắng sao chép tệp source
từ thư mục làm việc cục bộ sang tệp destination
của thư mục chung. Như dự đoán, chúng ta nhận được false
, và mã lỗi trong _LastError
sẽ là 5019 (FILE_NOT_EXIST
).
void OnStart()
{
PRTF(FileCopy(source, 0, destination, FILE_COMMON)); // false / FILE_NOT_EXIST(5019)
...
2
3
4
Do đó, chúng ta sẽ tạo một tệp nguồn theo cách thông thường, ghi một số dữ liệu và đẩy nó lên đĩa.
int handle = PRTF(FileOpen(source, FILE_TXT | FILE_WRITE)); // 1
PRTF(FileWriteString(handle, "Test Text\n")); // 22
FileFlush(handle);
2
3
Vì tệp vẫn đang mở và quyền FILE_SHARE_READ
không được chỉ định khi mở, việc truy cập vào tệp theo cách khác (bỏ qua handle) vẫn bị chặn. Do đó, lần thử sao chép tiếp theo sẽ thất bại một lần nữa.
PRTF(FileCopy(source, 0, destination, FILE_COMMON)); // false / CANNOT_OPEN_FILE(5004)
Hãy đóng tệp và thử lại. Nhưng trước tiên, chúng ta sẽ xuất các thuộc tính của tệp kết quả vào nhật ký: thời điểm tạo và sửa đổi. Cả hai thuộc tính sẽ chứa dấu thời gian hiện tại của máy tính của bạn.
FileClose(handle);
PRTF(FileGetInteger(source, FILE_CREATE_DATE)); // 1629757115, ví dụ
PRTF(FileGetInteger(source, FILE_MODIFY_DATE)); // 1629757115, ví dụ
2
3
Hãy đợi 3 giây trước khi gọi FileCopy
. Điều này sẽ cho phép bạn thấy sự khác biệt trong thuộc tính của tệp gốc và bản sao của nó. Khoảng dừng này không liên quan gì đến việc khóa tệp trước đó: chúng ta có thể sao chép ngay sau khi đóng tệp, hoặc thậm chí trong khi ghi nếu tùy chọn FILE_SHARE_READ
được bật.
Sleep(3000);
Hãy sao chép tệp. Lần này thao tác thành công. Hãy xem thuộc tính của bản sao.
PRTF(FileCopy(source, 0, destination, FILE_COMMON)); // true
PRTF(FileGetInteger(destination, FILE_CREATE_DATE, true)); // 1629757118, +3 giây
PRTF(FileGetInteger(destination, FILE_MODIFY_DATE, true)); // 1629757115, ví dụ
2
3
Mỗi tệp có thời gian tạo riêng (đối với bản sao, nó muộn hơn 3 giây so với tệp gốc), nhưng thời gian sửa đổi thì giống nhau (bản sao đã kế thừa thuộc tính của tệp gốc).
Bây giờ hãy thử di chuyển bản sao trở lại thư mục cục bộ. Điều này không thể thực hiện được nếu không có tùy chọn FILE_REWRITE
vì không có quyền ghi đè lên tệp gốc.
PRTF(FileMove(destination, FILE_COMMON, source, 0)); // false / FILE_CANNOT_REWRITE(5020)
Bằng cách thay đổi giá trị của tham số, chúng ta sẽ đạt được việc chuyển tệp thành công.
PRTF(FileMove(destination, FILE_COMMON, source, FILE_REWRITE)); // true
Cuối cùng, tệp gốc cũng được xóa để giữ môi trường sạch sẽ cho các thử nghiệm mới với script này.
...
FileDelete(source);
}
2
3