Lấy thuộc tính của tệp
Trong quá trình làm việc với tệp, ngoài việc trực tiếp ghi và đọc dữ liệu, thường cần phân tích các thuộc tính của chúng. Một trong những thuộc tính chính, kích thước tệp, có thể được lấy bằng hàm FileSize
. Nhưng còn một số đặc điểm khác có thể được yêu cầu bằng cách sử dụng FileGetInteger
.
Xin lưu ý rằng hàm FileSize
yêu cầu một handle tệp đã mở. FileGetInteger
có một số thuộc tính, bao gồm kích thước, có thể được nhận biết qua tên tệp mà không cần mở tệp trước.
ulong FileSize(int handle)
Hàm này trả về kích thước của một tệp đã mở dựa trên mô tả của nó. Trong trường hợp xảy ra lỗi, kết quả bằng 0, đây là một kích thước hợp lệ cho việc thực thi bình thường của hàm, vì vậy bạn nên luôn phân tích các lỗi tiềm ẩn bằng cách sử dụng _LastError
(hoặc GetLastError).
Kích thước tệp cũng có thể được lấy bằng cách di chuyển con trỏ đến cuối tệp bằng FileSeek(handle, 0, SEEK_END)
và gọi FileTell(handle)
. Hai hàm này đã được mô tả trong phần trước.
long FileGetInteger(int handle, ENUM_FILE_PROPERTY_INTEGER property)
long FileGetInteger(const string filename, ENUM_FILE_PROPERTY_INTEGER property, bool common = false)
Hàm này có hai tùy chọn: làm việc thông qua mô tả tệp đã mở, và theo tên tệp (bao gồm cả tệp chưa mở).
Hàm trả về một trong những thuộc tính của tệp được chỉ định trong tham số property
. Danh sách các thuộc tính hợp lệ khác nhau cho từng tùy chọn (xem bên dưới). Mặc dù kiểu giá trị là long
, tùy thuộc vào thuộc tính được yêu cầu, nó có thể chứa không chỉ số nguyên mà còn datetime
hoặc bool
: hãy thực hiện ép kiểu cần thiết một cách rõ ràng.
Khi yêu cầu một thuộc tính theo tên tệp, bạn có thể sử dụng thêm tham số common
để chỉ định thư mục nào sẽ tìm kiếm tệp: thư mục terminal hiện tại MQL5/Files
(false
, mặc định) hoặc thư mục chung Users/<user_name>...MetaQuotes/Terminal/Common/Files
(true
). Nếu chương trình MQL đang chạy trong bộ kiểm tra, thư mục làm việc nằm trong thư mục của tác nhân kiểm tra (Tester/<agent>/MQL5/Files
), xem phần giới thiệu của chương Làm việc với tệp.
Bảng sau liệt kê tất cả các thành viên của ENUM_FILE_PROPERTY_INTEGER
.
Thuộc tính | Mô tả |
---|---|
FILE_EXISTS * | Kiểm tra sự tồn tại (tương tự FileIsExist) |
FILE_CREATE_DATE * | Ngày tạo tệp |
FILE_MODIFY_DATE * | Ngày sửa đổi cuối cùng |
FILE_ACCESS_DATE * | Ngày truy cập cuối cùng |
FILE_SIZE * | Kích thước tệp tính bằng byte (tương tự FileSize) |
FILE_POSITION | Vị trí con trỏ trong tệp (tương tự FileTell) |
FILE_END | Vị trí ở cuối tệp (tương tự FileIsEnding) |
FILE_LINE_END | Vị trí ở cuối chuỗi (tương tự FileIsLineEnding) |
FILE_IS_COMMON | Tệp được mở trong thư mục chung của terminal (FILE_COMMON) |
FILE_IS_TEXT | Tệp được mở dưới dạng văn bản (FILE_TXT) |
FILE_IS_BINARY | Tệp được mở dưới dạng nhị phân (FILE_BIN) |
FILE_IS_CSV | Tệp được mở dưới dạng CSV (FILE_CSV) |
FILE_IS_ANSI | Tệp được mở dưới dạng ANSI (FILE_ANSI) |
FILE_IS_READABLE | Tệp được mở để đọc (FILE_READ) |
FILE_IS_WRITABLE | Tệp được mở để ghi (FILE_WRITE) |
Các thuộc tính được phép sử dụng theo tên tệp được đánh dấu bằng dấu sao. Nếu bạn cố gắng lấy các thuộc tính khác, phiên bản thứ hai của hàm sẽ trả về lỗi 4003 (INVALID_PARAMETER
).
Một số thuộc tính có thể thay đổi trong khi làm việc với tệp đã mở: FILE_MODIFY_DATE
, FILE_ACCESS_DATE
, FILE_SIZE
, FILE_POSITION
, FILE_END
, FILE_LINE_END
(chỉ dành cho tệp văn bản).
Trong trường hợp xảy ra lỗi, kết quả của lệnh gọi là -1.
Phiên bản thứ hai của hàm cho phép bạn kiểm tra xem tên được chỉ định là tên của tệp hay thư mục. Nếu một thư mục được chỉ định khi lấy thuộc tính theo tên, hàm sẽ đặt mã lỗi nội bộ đặc biệt 5018 (ERR_MQL_FILE_IS_DIRECTORY
), trong khi giá trị trả về vẫn đúng.
Chúng ta sẽ kiểm tra các hàm trong phần này bằng tập lệnh FileProperties.mq5
. Nó sẽ hoạt động trên một tệp có tên được định nghĩa trước.
const string fileprop = "MQL5Book/fileprop";
Tại phần đầu của OnStart
, hãy thử yêu cầu kích thước bằng một mô tả sai (nó không được nhận qua lệnh gọi FileOpen
). Sau FileSize
, cần kiểm tra biến _LastError
, và FileGetInteger
ngay lập tức trả về một giá trị đặc biệt, một chỉ báo lỗi (-1).
void OnStart()
{
int handle = 0;
ulong size = FileSize(handle);
if(_LastError)
{
Print("FileSize error=", E2S(_LastError) + "(" + (string)_LastError + ")");
// Chúng ta sẽ nhận được: FileSize 0, error=WRONG_FILEHANDLE(5008)
}
PRTF(FileGetInteger(handle, FILE_SIZE)); // -1 / WRONG_FILEHANDLE(5008)
}
2
3
4
5
6
7
8
9
10
11
12
Tiếp theo, chúng ta tạo một tệp mới hoặc mở một tệp hiện có và đặt lại nó, sau đó ghi văn bản kiểm tra.
handle = PRTF(FileOpen(fileprop, FILE_TXT | FILE_WRITE | FILE_ANSI)); // 1
PRTF(FileWriteString(handle, "Test Text\n")); // 11
2
Chúng ta yêu cầu một cách chọn lọc một số thuộc tính.
PRTF(FileGetInteger(fileprop, FILE_SIZE)); // 0, chưa được ghi vào đĩa
PRTF(FileGetInteger(handle, FILE_SIZE)); // 11
PRTF(FileSize(handle)); // 11
PRTF(FileGetInteger(handle, FILE_MODIFY_DATE)); // 1629730884, số giây từ năm 1970
PRTF(FileGetInteger(handle, FILE_IS_TEXT)); // 1, bool true
PRTF(FileGetInteger(handle, FILE_IS_BINARY)); // 0, bool false
2
3
4
5
6
Thông tin về độ dài của tệp theo mô tả của nó tính đến bộ đệm lưu trữ hiện tại, và theo tên tệp, độ dài thực tế sẽ chỉ khả dụng sau khi tệp được đóng, hoặc nếu bạn gọi hàm FileFlush
(xem phần Ép buộc ghi bộ đệm vào đĩa).
Hàm trả về ngày và giờ dưới dạng số giây của kỷ nguyên tiêu chuẩn kể từ ngày 1 tháng 1 năm 1970, tương ứng với kiểu datetime
và có thể được đưa về kiểu này.
Yêu cầu về cờ mở tệp (chế độ của nó) thành công đối với phiên bản hàm có mô tả, cụ thể, chúng ta nhận được phản hồi rằng tệp là văn bản và không phải nhị phân. Tuy nhiên, yêu cầu tương tự tiếp theo cho tên tệp sẽ thất bại vì thuộc tính chỉ được hỗ trợ khi một handle hợp lệ được truyền vào. Điều này xảy ra mặc dù tên trỏ đến cùng tệp mà chúng ta đã mở.
PRTF(FileGetInteger(fileprop, FILE_IS_TEXT)); // -1 / INVALID_PARAMETER(4003)
Hãy đợi một giây, đóng tệp, và kiểm tra lại ngày sửa đổi (lần này theo tên, vì mô tả không còn hợp lệ).
Sleep(1000);
FileClose(handle);
PRTF(FileGetInteger(fileprop, FILE_MODIFY_DATE)); // 1629730885 / ok
2
3
Ở đây bạn có thể thấy rõ rằng thời gian đã tăng thêm 1.
Cuối cùng, hãy đảm bảo rằng các thuộc tính cũng khả dụng cho các thư mục (folders).
PRTF((datetime)FileGetInteger("MQL5Book", FILE_CREATE_DATE));
// Chúng ta sẽ nhận được: 2021.08.09 22:38:00 / FILE_IS_DIRECTORY(5018)
2
Vì tất cả các ví dụ trong sách đều nằm trong thư mục "MQL5Book", nó chắc chắn đã tồn tại. Tuy nhiên, thời gian tạo thực tế của bạn sẽ khác. Mã lỗi FILE_IS_DIRECTORY
trong trường hợp này được hiển thị cho chúng ta bởi macro PRTF
. Trong chương trình làm việc, lệnh gọi hàm nên được thực hiện mà không có macro, và sau đó mã nên được đọc trong _LastError
.