- •24.1. Іменування файлів у Windows
- •24.2. Створення і відкриття файлів
- •24.3. Закриття і видалення файлів
- •24.4. Запис даних у файл
- •24.5. Звільнення буферів файла
- •24.6. Читання даних з файла
- •24.7. Копіювання файла
- •24.8. Переміщення файла
- •24.9. Заміщення файла
- •24.10. Робота з покажчиком позиції файла
- •24.11. Визначення і зміна атрибутів файла
- •24.12. Визначення і зміна розмірів файла
- •24.13. Блокування файла
- •24.14. Отримання інформації про файл
24.10. Робота з покажчиком позиції файла
Перш ніж розбиратися з функцією для роботи з покажчиком позиції файла, розглянемо формат самого покажчика позиції файла. Покажчик позиції файла складається з двох значень типу dword, які називатимуться старша і молодша частина покажчика позиції файла відповідно. Отже, покажчик позиції має довжину в 64 біта. Якщо довжина файла не перевищує 2-х гігабайт без 2-х байт, тобто 231-2 байти, то в покажчику позиції використовується тільки його молодша частина, яка розглядається як ціле число зі знаком, але при цьому старша частина покажчика позиції має бути встановлена в null.
Для роботи з покажчиком позиції файла служить функція SetFilePointer(), яка має наступний прототип:
DWORD SetFilePointer(
HANDLE hFile, // дескриптор файла
LONG lDistanceToMove, // молодша частина зсуву покажчика в байтах
PLONG lpDistanceToMoveHigh, // покажчик на старшу частину зсуву покажчика в байтах
DWORD dwMoveMethod); // початкова точка зсуву
У разі вдалого завершення ця функція повертає молодшу частину нової позиції покажчика файла, а за адресою, заданою параметром lpDistanceToMoveHigh, записує старшу частину нової позиції покажчика файла. Якщо функція встановлює старшу частину покажчика позиції в null, то молодша частина покажчика позиції представлена додатним цілим числом. У разі невдалого завершення функція SetFilePointer() повертає значення -1 і при цьому встановлює значення параметра lpDistanceToMoveHigh в null. Якщо ж значення цього параметра не встановлене в null, то повернуте значення -1 може бути і дійсною молодшою частиною покажчика позиції. У цьому випадку треба перевірити код останньої помилки, який повертає функція GetLastError(). Якщо цей код дорівнює no_error, то помилки немає, а інакше виконання функції SetFilePointer() завершилося невдало. Тепер коротко опишемо призначення параметрів функції SetFilePointer().
Параметр hFile повинен містити дескриптор файла, причому сам файл має бути відкритий в режимі читання або запису.
Параметр lDistanceToMove повинен містити молодшу частину зсуву для покажчика позиції файла. Якщо значення параметра lpDistanceToMoveHigh встановлене в null, то значення цього параметра розглядається як ціле число зі знаком. У разі додатного числа функція виконує зсув покажчика вперед на задане число байт, а у разі негативного числа виконується зсув назад.
Параметр lpDistanceToMoveHigh повинен містити адресу старшої частини зсуву для покажчика позиції файла. Старша і молодша частині покажчика позиції розглядаються як ціле число зі знаком. Якщо значення цього параметра дорівнює null, то зсув задається тільки молодшою частиною.
Параметр dwMoveMethod задає початкову точку, від якої виконується зсув покажчика позиції. Цей параметр може приймати тільки одне з наступних значень:
file_begin - зсув від початку файла;
file_current - зсув від поточної позиції файла;
file_end - зсув від кінця файла.
У лістингу 24.8 приведена програма, яка читає запис файла, заздалегідь встановивши на цей запис покажчик. До речі, таке читання записів файла називається прямим доступом до файла. У загальному випадку прямий доступ до файла має на увазі читання запису із заданим значенням ключа, який визначається вмістом одного або декількох полів запису. Правда, у цьому випадку треба знати залежність покажчика позиції файла від значення ключа запису.
// Лістинг 24.8. Встановлення покажчика позиції файла за допомогою функції SetFilePointer()
#include "stdafx.h"
int main()
{
HANDLE hFile; // дескриптор файла
wchar_t lpszFileName[] = L"C:\\Users\\Shogun\\Documents\\demo_file.dat";
long n; // для номера запису
long p; // для покажчика позиції
DWORD dwBytesRead; // число байтів, які треба прочитати
int m; // число прочитаних байт
// відкриваємо файл для читання
hFile = CreateFile(
lpszFileName, // ім'я файла
GENERIC_READ, // читання із файла
0, // монопольний доступ до файла
NULL, // захисту немає
OPEN_EXISTING, // відкриваємо існуючий файл
FILE_ATTRIBUTE_NORMAL, // звичайний файл
NULL // шаблона немає
);
// перевіряємо на успішність відкриття
if (hFile == INVALID_HANDLE_VALUE) {
std::cerr << "Create file failed." << std::endl
<< "The last error code: " << GetLastError() << std::endl;
std::cout << "Press any key to finish.";
std::cin.get();
return 0;
}
// вводимо номер потрібного запису
std::cout << "Input a number from 0 to 9: ";
std::cin >> n;
// зсуваємо покажчик позиції файла
p = SetFilePointer(hFile, n * sizeof(int), NULL, FILE_BEGIN);
if(p == -1) {
std::cerr << "Set file pointer failed." << std::endl
<< "The last error code: " << GetLastError() << std::endl;
CloseHandle(hFile);
std::cout << "Press any key to finish.";
std::cin.get();
return 0;
}
// виводимо на консоль значення покажчика позиції файла
std::cout << "File pointer: " << p << std::endl;
// читаємо дані із файла
if (!ReadFile(
hFile, // дескриптор файла
&m, // адреса буфера, куди читаємо дані
sizeof(m), // число байт, які треба прочитати
&dwBytesRead, // число прочитаних байт
(LPOVERLAPPED)NULL // читання синхронне
))
{
std::cerr << "Read file failed." << std::endl
<< "The last error code: " << GetLastError() << std::endl;
CloseHandle(hFile);
std::cout << "Press any key to finish.";
std::cin.get();
return 0;
}
// виводимо прочитане число на консоль
std::cout << "The read number: " << m << std::endl;
// закриваємо дескриптор файла
CloseHandle(hFile);
std::cin.get();
return 0;
}
За допомогою функції SetFilePointer() можна також визначити поточний стан покажчика позиції файла. Для цього треба просто зсунути покажчик файла від поточної позиції на нульове число байт. У результаті функція SetFilePointer() поверне поточний стан покажчика позиції файла.
Починаючи з операційної системи Windows 2000, для роботи з покажчиком позиції файла можна використовувати функцію SetFilePointerEx(), яка простіша у використанні і має наступний прототип:
BOOL SetFilePointerEx(
HANDLE hFile, // дескриптор файла
LARGE_INTEGER liDistanceToMove, // зсув у байтах
PLARGE_INTEGER lpNewFilePointer, // новий покажчик позиції файла
DWORD dwMoveMethod); // початкова точка зсуву
У разі вдалого завершення ця функція повертає ненульове значення, інакше - false. Перший та останній параметри цієї функції мають таке ж призначення, як і у функції SetFilePointer(). Тому коротко опишемо параметри, які залишилися.
Параметр liDistanceToMove задає зсув покажчика позиції файла, який розглядається як ціле число зі знаком. У разі додатного числа покажчик позиції зсувається вперед, а у разі від’ємного - назад.
Параметр lpNewFilePointer повинен вказувати на об’єднання типу LARGE_INTEGER, в яке функція SetFilePointerEx() поверне нове значення індикатора позиції файла. Об’єднання типу LARGE_INTEGER має наступний формат:
typedef union _LARGE_INTEGER
{
struct
{
DWORD LowPart; // молодша частина
LONG HighPart; // старша частина
};
LONGLONG QuadPart; // всі частини
} LARGE_INTEGER, *PLARGE_INTEGER;
Якщо значення параметра lpNewFilePointer дорівнює null, то нове значення індикатора позиції не повертатиметься.
У лістингу 24.9 приведена програма, яка для встановлення індикатора позиції використовує функцію SetFilePointerEx(), а потім читає з файла запис, на який встановлений індикатор позиції.
// Лістинг 24.9. Встановлення покажчика позиції файла при допомозі функції SetFilePointerEx()
#include "stdafx.h"
// #define _WIN32_WINNT 0x0500 // або визначити цей макрос замість функції, якщо нова платформа
extern "C" WINBASEAPI BOOL WINAPI SetFilePointerEx(
HANDLE hFile,
LARGE_INTEGER liDistanceToMove,
PLARGE_INTEGER lpNewFilePointer,
DWORD dwMoveMethod
);
int main()
{
HANDLE hFile; // дескриптор файла
wchar_t lpszFileName[] = L"C:\\Users\\Shogun\\Documents\\demo_file.dat";
int n; // для номера запису
LARGE_INTEGER p, q; // для покажчика позиції
DWORD dwBytesRead; // число байт, які потрібно прочитати
int m; // прочитане число байт
// відкриваємо файл для читання
hFile = CreateFile(
lpszFileName, // ім'я файла
GENERIC_READ, // читання із файла
0, // монопольний доступ до файла
NULL, // захисту немає
OPEN_EXISTING, // відкриваємо існуючий файл
FILE_ATTRIBUTE_NORMAL, // звичайний файл
NULL // шаблона немає
);
// перевіряємо на успішність відкриття
if (hFile == INVALID_HANDLE_VALUE)
{
std::cerr << "Create file failed." << std::endl
<< "The last error code: " << GetLastError() << std::endl;
std::cout << "Press any key to finish.";
std::cin.get();
return 0;
}
// вводимо номер потрібного запису
std::cout << "Input a number from 0 to 9: ";
std::cin >> n;
q.HighPart = 0;
q.LowPart = n * sizeof(int);
// зсуваємо покажчик позиції файла
if(!SetFilePointerEx(hFile, q, &p, FILE_BEGIN))
{
std::cerr << "Set file pointer failed." << std::endl
<< "The last error code: " << GetLastError() << std::endl;
CloseHandle(hFile);
std::cout << "Press any key to finish.";
std::cin.get();
return 0;
}
// виводимо на консоль значення покажчика позиції файла
std::cout << "File pointer: " << p.HighPart << ' ' << p.LowPart << std::endl;
std::cin.get();
// читаємо дані із файла
if (!ReadFile(
hFile, // дескриптор файла
&m, // адреса буфера, куди читаємо дані
sizeof(m), // число байт, які потрібно читати
&dwBytesRead, // число прочитаних байт
(LPOVERLAPPED)NULL // читання синхронне
))
{
std::cerr << "Read file failed." << std::endl
<< "The last error code: " << GetLastError() << std::endl;
CloseHandle(hFile);
std::cout << "Press any key to finish.";
std::cin.get();
return 0;
}
// виводимо прочитане число на консоль
std::cout << "The read number: " << m << std::endl;
// закриваємо дескриптор файла
CloseHandle(hFile);
std::cin.get();
return 0;
}
