Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lek13_14.doc
Скачиваний:
9
Добавлен:
13.07.2019
Размер:
695.3 Кб
Скачать

6. Запись данных в файл

Для записи данных в файл предназначена функция WriteFile(). Её синтаксис следующий:

BOOL WriteFile (HANDLE hFipe, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, POVERLAPPED lpOverlapped )

Параметры:

hFipe – хэндл открытого файла.

lpBuffer – указатель на буфер, данные из которого будут записаны в файл.

nNumberOfBytesToWrite – размер буфера для записи.

lpNumberOfBytesWritten – количества байт данных, действительно записанных в файл.

lpOverlapped – указатель на структуру OVERLAPPED.

Возвращаемое значение. При успешном выполнении – TRUE, при ошибке - FALSE. В последнем случае для уточнения причины возникновения ошибки можно воспользоваться функцией GetLastError().

Для того, чтобы возможна была запись данных в файл, файл должен быть открыт с флагом GENERIC_WRITE.

Аргументы функции WriteFile(). Значение первого аргумента, hFile, очевидно. Это хэндл файла, в который собираемся произвести запись.

Второй аргумент, lpBuffer, - это указатель на буфер, данные из которого хотим записать в файл. Число байтов, которые хотим записать в файл, должно быть указано в третьем аргументе, nNumberOfBytesToWrite. После того, как функция выполнит свою работу, в буфер, на который указывает четвёртый аргумент, lpNumberOfBytesWritten, будет записано число байтов, записанных в файл. Последний аргумент, lpOverlapped, который указывает на структуру типа OVERLAPPED, которая используется только в случае асинхронного ввода – и должен быть равен NULL.

Как и в случае чтения файла, запись данных начинается с того места, на которое указывает указатель файла. После каждой операции чтения указатель файла смещается на величину, равную тому количеству байтов, которые были записаны в файл.

Если функция отработала нормально, то она возвращает значение TRUE. Значение FALSE возвращается в том случае, если при работе функции произошла ошибка.

Блокировка и разблокировка файла

Проблема связана с возможностью одновременного доступа к файлу нескольких процессов.

Представим себе такую ситуацию. С базой данных большого предприятия работает одновременно несколько человек. Если они имеют право только читать данные из файла, никаких проблем не возникает. Но, естественно, если двум или более сотрудникам потребуется одновременно произвести запись в одно и то же место файла? Целостность данных будет нарушена. Может быть, открывать файл только с флагом FILE_SHARE_READ? Но тогда никто, кроме открывшего файл, не сможет произвести запись в файл.

Простейший выход, который можно найти - это блокировка файлов. Другими словами, если нам необходим файл для монопольного использования в течение какого-то времени, мы можем заблокировать файл. Если флаги FILE_SHARE_* влияют на весь файл в целом, то блокировать можно только какую-то часть файла. Перед тем, как производить запись в файл, нам необходимо убедиться в том, что никто, кроме нас, не сможет в то же время произвести запись в то же место файла. В этом нам поможет функция LockFile(). Описание этой функции, взятое из файла заголовков winbase.h, я привожу ниже:

BOOL LockFile (HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh).

На первом аргументе, hFile, останавливаться не стоит - это хэндл блокируемого файла. Второй и третий аргументы, dwFileOffsetLow и dwFileOffsetHigh соответственно, содержат младшие тридцать два разряда и старшие тридцать два разряда смещения той части файла которую необходимо блокировать. Четвёртый и пятый аргументы, nNumberOfBytesToLockLow и nNumberOfBytesToLockHigh, содержат младшую и старшую части числа, определяющего размер блокируемой области в байтах.

При успешном завершении работы функция возвращает TRUE. Если функция вернула FALSE, нам необходимо разобраться, в чём причина ошибки.

Если заблокировали какой-то участок файла, то никто, кроме нас, не сможет осуществить обращение к этой области файла, то есть опасности разрушения данных из-за одновременного доступа к файлу нет.

А как нам поступить в том случае, если мы собираемся добавлять данные в конец файла? ТОЧНО ТАК ЖЕ! Нам необходимо блокировать участок файла ЗА КОНЦОМ ФАЙЛА, после чего спокойно производить туда запись.

При помощи функции LockFileEx() можем более гибко управлять блокировкой файла. Эта функция в файле winbase.h описана следующим образом:

BOOL LockFileEx (HANDLE hFile, DWORD dwFlags, DWORD dwReserved, DWORD nNumberOffiytesToLockLow, DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped);

Что принципиально нового предлагает нам эта функция по сравнению с функцией LockFile()? Обратим внимание на второй аргумент, dwFlags. Их возможные значения и назначение я привожу в таблице ниже:

Флаг

Назначение

LOCKFILE_FAIL_IMMEDIATELY

Если заблокировать область не удаётся, функция НЕМЕДЛЕННО возвращает управление. Если флаг не установлен, функция ждёт, пока область будет разблокирована, чтобы получить к ней доступ.

LOCKFILE_EXCLUSIVE_LOCK

Если флаг установлен, то другие пользователи не могут ни читать, ни записывать в файл. В противном случае другим пользователям разрешено чтение из файла.

Со вторым флагом, LOCKFILE_EXCLUSIVE_LOCK, кажется, всё ясно. Скажу о первом флаге, LOCKFILE_FAIL_IMMEDIATELY. Дело в том, что если нужно заблокировать файл, а он уже заблокирован другим пользователем, то функция LockFile() сразу же вернёт нам управление. Нам придётся постоянно вызывать функцию LockFile() до тех пор, пока не сможем заблокировать требуемую область файла. Задачу ожидания освобождения области можно возложить на функцию LockFileEx(), не устанавливая флага LOCKFILE_FAIL_IMMEDIATELY.

Третий аргумент зарезервирован для дальнейшего использования и должен быть установлен в нуль. Четвёртый и пятый аргументы определяют размер блокируемой области точно таким же образом, как это делается в функции LockFile().

ВОПРОС - а как же нам указать смещение в файле, начиная с которого мы хотим блокировать область? Для этого существует шестой аргумент, lpOverlapped. Он указывает на структуру типа OVERLAPPED, которая описана в файле winbase.h следующим образом:

typedef struct _OVERLAPPED {

DWORD Internal; //состояние системы

DWORD InternalHigh; //число прочитанных или записанных байтов

DWORD Offset; //младшие разряды смещения в файле

DWORD OffsetHigh; //старшие разряды смещения в файле

HANDLE hEvent; //хэндл объекта, сигнализирующего об окончании операции ввода - вывода.

} OVERLAPPED, *LPOVERLAPPED;

Функция LockFileEx() использует только поля Offset и OffsetHigh. В них до вызова функции должны быть записаны соответственно младшие и старшие тридцать два разряда смещения области, которую необходимо блокировать.

Так же, как и функция LockFile(), функция LockFileEx() возвращает значение TRUE в случае успешного завершения и FALSE, если встретилась какая-то ошибка.

Раз мы получили временный эксклюзивный доступ к области файла, то, естественно, после окончания работы с этой областью необходимо её разблокировать. Это делается при помощи функции UnlockFile(). Эта функция описана в файле winbase.h, привожу это описание ниже:

BOOL UnlockFile (HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD NumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh);

Назначение аргументов этой функции совпадает с назначением аргументов функции LockFileQ, поэтому я не стану останавливаться на них. Единственное, на что нужно обратить внимание, что разблокировать нужно ИМЕННО ТУ область файла, которая была ранее заблокирована.

В недрах Win32 API существует и функция UnlockFileEx(). Она описана в файле winbase.h, привожу её описание ниже:

BOOL UnlockFileEx (HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED IpOverlapped);

Аргументы этой функции подобны аргументам функции LockFileEx(), поэтому, надеюсь, назначение аргументов понятно.

Замечание. Дело в том, что не все функции, имеющиеся в Win32 API, реализованы в Windows 9х. Многие функции реализованы как заглушки. Поэтому, если в Windows 9х при вызове функции она возвращает вам FALSE, хотя, кажется, всё в порядке, попробуйте вызвать функцию GetLastError(). Если возвращённый код ошибки равен 120 (ERROR_CALL_NOT_IM­PLEMEN­TED), то считайте, что не повезло, эта функция как раз и реализована как заглушка. Придётся изменять код программы и искать другие функции.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]