Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Операционные Системы

.pdf
Скачиваний:
37
Добавлен:
02.03.2016
Размер:
1.94 Mб
Скачать

Лабораторная работа №7. Файловый ввод-вывод.

Цель занятия

Знакомство с подсистемой ввода-вывода системы Windows NT.

Научиться

-Создавать объект ядра «файл».

-Выполнять синхронные операции над файлами.

-Выполнять асинхронные операции над файлами с использованием:

Синхронизации с объектом ядра «файл»

Синхронизации с объектом ядра «событие»

Синхронизации с использованием оповестительного ввода-вывода

(alterable I/O).

Синхронизация с использованием портов завершения ввода-вывода.

-Использовать объект «проекция файла»

Теория

Модель системы ввода-вывода Windows согласуется с концепцией большинства ОС, где все устройства представлены прикладному программисту как файл. ОС пытается, насколько это, возможно, скрыть от разработчиков различия между устройствами. Открыв устройство, вы используете одни и те же функции для чтения и записи независимо от того, с каким устройством вы обмениваетесь информацией.

Для осуществления ввода-вывода, прежде всего надо открыть устройство и получить его описатель. Способ получения описателя зависит от типа устройства, но, как правило, используется функция CreateFile.

Таблица 11. Функции для открытия различных устройств.

Устройство

Функция для открытия устройства

 

 

 

 

Файл

CreateFile(Полный путь файла или UNC);

 

 

 

 

Каталог

CreateFile(Полный путь каталога или UNC);

 

 

 

 

Логический диск

CreateFile(\\.\x:); x – имя логического диска

 

 

 

 

Физический диск

CreateFile(\\.\PHYSICALDRIVEx); x – номер

 

 

 

 

Последовательный порт

CreateFile(COMx); x – номер

 

 

 

 

Параллельный порт

CreateFile(LPTx); x – номер

 

 

 

 

Сервер почтового ящика

CreateMailslot(\\.\mailslot\имя);

 

 

 

 

Клиент почтового ящика

CreateFile(\\сервер\mailslot\имя);

 

 

 

71

Сервер именованного канала

CreateNamedPipe(\\.\Pipe\Имя);

 

 

 

 

Клиент именованного канала

CreateFile(\\сервер\pipe\имя);

 

 

 

 

Консоль

CreateConsoleScreenBuffer, GetStdHandle

 

 

 

 

Сокет

socket, accept или AcceptEx

 

 

 

 

HANDLE CreateFile(

 

 

LPCTSTR lpFileName,

//

Имя файла

DWORD dwDesiredAccess,

//

Режим доступа

DWORD dwShareMode,

// Режим

разделения

 

 

LPSECURITY_ATTRIBUTES lpSecurityAttributes, //

Дескриптор защиты

 

 

DWORD dwCreationDisposition,

// Параметры

создания

 

 

DWORD dwFlagsAndAttributes,

// Атрибуты

файла

 

 

HANDLE hTemplateFile

// Описатель

шаблона

 

 

);

 

 

LPCTSTR lpFileName указывает тип и имя устройства. Для дисковых файлов указывается полный путь либо UNC путь. Максимальная длина пути равна MAX_PATH (260), однако можно преодолеть это ограничение, указав перед именем “\\?\” это позволит указать имя в формате UNICODE, длиной до 32 000 символов, но каждый компонент пути ограничен

MAX_PATH.

DWORD dwDesiredAccess определяет, как будет производиться обмен данными с устройством.

 

Значение

 

 

Описание

 

 

 

 

 

 

 

 

 

 

0

Считывание

или

запись

на

устройство

 

 

производиться не будут. Файл открыт только для

 

 

изменения

конфигурационных

параметров

 

 

устройства.

 

 

 

 

 

 

 

 

GENERIC_READ

Разрешает доступ к устройству только для чтения

 

 

 

 

 

 

 

 

 

72

 

 

 

 

GENERIC_WRITE

Разрешает доступ к устройству только для записи

 

 

GENERIC_READ|

Разрешает доступ для чтения и записи.

GENERIC_WRITE

 

 

 

DWORD dwShareMode определяет привилегии при совместном доступе к устройству.

Значение

Описание

 

 

0

Требуется монопольный доступ к устройству

 

 

FILE_SHARE_READ

Другие процессы не могут записывать на

 

устройство

 

 

FILE_SHARE_WRITE

Другие процессы не могут читать с устройства

 

 

FILE_SHARE_READ |

Другие процессы могут и писать и читать с

FILE_SHARE_WRITE

устройства

 

 

LPSECURITY_ATTRIBUTES lpSecurityAttributes – дескриптор защиты, который применим только в файловой системе NTFS. Для защиты по умолчанию NULL.

DWORD dwCreationDisposition задаѐт параметры открытия дисковых файлов

 

Значение

 

 

Описание

 

 

 

 

 

CREATE_NEW

 

Функция должна создать новый файл. Если файл

 

 

 

 

существует, функция не выполняется.

 

 

 

 

 

CREATE_ALWAYS

 

Функция создаѐт новый файл в независимости от

 

 

 

 

его существования.

 

 

 

 

 

 

OPEN_EXISTING

 

Функция открывает существующий файл. Если он

 

 

 

 

отсутствует, то функция не выполняется.

 

 

 

 

 

OPEN_ALWAYS

 

Функция откроет существующий файл или

 

 

 

 

создаст новый, если его нет.

 

 

 

 

 

 

TRUNCATE_EXISTING

 

Функция открывает существующий файл и

 

 

 

 

обнуляет его размер.

 

 

 

 

 

 

 

DWORD

dwFlagsAndAttributes

используется

для двух целей:

позволяет

устанавливать

флаги для

оптимизации

взаимодействия с

 

 

 

 

 

 

 

 

 

 

 

73

 

 

устройством, а, так же, если устройство является файлом, – установить его атрибуты. Ниже даны некоторые, наиболее важные, флаги и атрибуты.

Значение

Описание

 

 

FILE_FLAG_NO_BUFFERING

Этот флаг указывает, что доступ к файлу

 

должен производиться без буферизации.

 

Флаг налагает некоторые ограничения:

 

Смещения при доступе к файлу должны

 

быть кратны сектору дискового тома.

 

Число считываемых и записываемых байт

 

должно быть кратно размеру сектора.

 

Адрес буфера должен быть кратен

 

размеру сектора.

 

 

FILE_FLAG_SEQUENTIAL_S

Позволяет подсистеме I/O оптимизировать

CAN

последовательный доступ к данным файла.

 

 

 

FILE_FLAG_RANDOM_ACCESS

Позволяет подсистеме I/O оптимизировать

 

доступ к данным файла по случайным

 

смещениям.

 

 

FILE_FLAG_WRITE_THROUGH

Определяет сквозное кэширование записи

 

в файл.

 

 

FILE_FLAG_OVERLAPPED

Этот флаг задаѐт асинхронный обмен

 

данными с файлом.

 

 

FILE_ATTRIBUTE_NORMAL

Файл не имеет атрибутов

 

 

FILE_ATTRIBUTE_READONLY

Файл только для чтения

 

 

…Другие атрибуты файла

 

 

 

HANDLE hTemplateFile – описатель уже открытого файла или NULL. Указывает файл, атрибуты которого должны быть назначены создаваемому файлу.

Возвращаемое значение

Вслучае удачи возвращает описатель файла или устройства, который закрывается функцией CloseHandle.

Вслучае ошибки возвращается значение INVALID_HANDLE_VALUE (0xFFFFFFF)

74

Пример 22. Вызов функции создания файла.

// Открытие существующего файла для записи и асинхронного доступа без //буферизации

HANDLE h = CreateFile("C:\\Sample.txt", GENERIC_WRITE,

FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING |

FILE_FLAG_OVERLAPPED, NULL);

// Открытие логического диска A:

HANDLE h = CreateFile("\\\\.\\A:", GENERIC_READ | GENERIC_WRITE,

FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0,

NULL);

// Открытие последовательного порта

HANDLE h = CreateFile("COM1", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0,

NULL);

// Проверка результата функции if (h != INVALID_HANDLE_VALUE)

{

CloseHandle(h);

} else printf(―Ошибка!‖);

Функции работы с файлами

В системе Windows 2000 адресация к данным файла производится через 64-битный указатель, что, теоретически, ограничивает размер файла 264 байт (18 экзабайт). В настоящий момент только файловая система NTFS поддерживает 64-разрядную адресацию. Системы FAT16 и FAT32 определяют максимальный фала в 232 (4 ГБ) байт. Указатель создаѐтся при открытии файла, и указывает на начальную позицию, с которой будет выполняться следующая операция чтения или записи (только при синхронном доступе к файлу!). Каждая операция чтения или записи сдвигает файловый указатель на число считанных или записанных байт.

75

Таблица 12. Получение размера файла.

DWORD GetFileSize

(

HANDLE hFile, // описатель файла

LPDWORD lpFileSizeHigh // старшие 32 разряда

);

HANDLE hFile описатель файла

LPDWORD lpFileSizeHigh – старшие 32 разряда размера файла. Можно передать NULL, если не интересует.

Возвращаемое значение

младшие 32 разряда размера файла

в случае ошибки возвращается INVALID_FILE_SIZE

Пример

HANDLE hFile = CreateFile(…);

DWORD dwLow, dwHigh;

 

__int64

Size;

 

dwLow =

GetFileSize(hFile, &dwHigh);

Size = dwHigh; Size<<=32; Size+=dwLow;

 

 

Таблица 13. Перемещение указателя файла.

 

 

 

DWORD SetFilePointer(

 

HANDLE hFile,

// Описатель файла

LONG lDistanceToMove, // младшие 32 бита смещения

 

 

// указателя

PLONG lpDistanceToMoveHigh, // старшие 32 бита

 

 

// смещения указателя

DWORD dwMoveMethod // Стартовая точка для

смещения

 

 

);

 

 

Стартовая точка для смещения:

FILE_BEGIN – смещать относительно начала файла. FILE_END – смещать относительно конца файла.

FILE_CURRENT – смещать относительно текущего значения указателя.

Возвращаемое значение

76

Новое смещение в файле в случае удачи.

INVALID_SET_FILE_POINTER в случае ошибки. Дополнительно требуется проверить результат функции, что GetLastError() != 0.

Пример

HANDLE hFile = CreateFile(…);

if (SetFilePointer(hFile, 1024, NULL, FILE_BEGIN) = INVALID_SET_FILE_POINTER)

{

if (GetLastError()!=0) printf(―Ошибка!‖); else printf(―OK!‖);

}

Таблица 14. Установка маркера конца файла.

BOOL SetEndOfFile(HANDLE hFile)

HANDLE hFile – описатель файла

Возвращаемое значение

TRUE в случае удачи.

Пример

Установка размера файла в 1 МБ

HANDLE hFile = CreateFile(…);

SetFilePointer(hFile,1024*1024,NULL, FILE_BEGIN); SetEndOfFile(hFile);

SetFilePointer(hFile, 0, NULL, FILE_BEGIN);

Синхронный ввод-вывод

Синхронный ввод-вывод осуществляется функциями ReadFile и WriteFile. При этом вызывающий поток блокируется до завершения операции. Операции с файлами происходят синхронно, если при его создании не был установлен флаг FILE_FLAG_OVERLAPPED.

Таблица 15. Функция ReadFile.

BOOL ReadFile(

HANDLE hFile, // описатель файла

LPVOID lpBuffer,// буфер для считывания данных

DWORD nNumberOfBytesToRead, // сколько байт читать LPDWORD lpNumberOfBytesRead,// истинное значение

// считанных байт

LPOVERLAPPED lpOverlapped // указатель на // структуру OVERLAPPED

77

);

HANDLE hFile описатель файла

LPVOID lpBuffer – буфер, куда будут помещены считанные данные. DWORD nNumberOfBytesToRead – число байт для чтения. Должно быть меньше или равно размеру буфера.

LPDWORD lpNumberOfBytesRead – указатель на переменную типа

DWORD для помещения результата об истинном значении считанных байт.

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

применяющаяся при асинхронном доступе к файлу. Для синхронного доступа указывается NULL.

Возвращаемое значение

Если запрашиваемая синхронная операция успешно завершена, то TRUE. При ошибке FALSE.

Если запрашиваемая асинхронная операция успешно завершена как синхронная, то TRUE

Если запрашиваемая асинхронная операция не завершена, то FALSE.

Требуется проверить, что GetLastError() = ERROR_IO_PENDING, что говорит о выполняющейся асинхронной операции. Если это не так, то результат ввода-вывода закончился с ошибкой.

Таблица 16. Функция WriteFile

BOOL WriteFile(

//описатель файла

HANDLE hFile,

//буфер для записи данных

LPVOID lpBuffer,

//сколько байт писать

DWORD nNumberOfBytesToWrite,

//истинное значение записанных байт

LPDWORD lpNumberOfBytesWritten,

//указатель на структуру OVERLAPPED

LPOVERLAPPED lpOverlapped );

HANDLE hFile описатель файла

LPVOID lpBuffer – буфер, откуда брать данные для записи данные. DWORD nNumberOfBytesToRead – число байт для записи. Должно быть меньше или равно размеру буфера.

LPDWORD lpNumberOfBytesRead – указатель на переменную типа

DWORD для помещения результата об истинном значении записанных байт.

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

78

OVERLAPPED, применяющейся при асинхронном доступе к файлу. Для синхронного доступа указывается NULL.

Возвращаемое значение

Если запрашиваемая синхронная операция успешно завершена, то TRUE. При ошибке FALSE.

Если запрашиваемая асинхронная операция успешно завершена как синхронная, то TRUE.

Если запрашиваемая асинхронная операция не завершена, то FALSE.

Требуется проверить, что GetLastError() == ERROR_IO_PENDING, что говорит о выполняющейся асинхронной операции. Если это не так, то результат ввода-вывода закончился с ошибкой.

Пример 23. Пример синхронной операции с файлом.

#define BUFSIZE 4096

//Исходный файл (должен существовать) const char szSrc[] = "С:\\Sample.txt";

//Конечный файл

const char szTgt[] = "С:\\New.txt"; int _tmain()

{

//Всегда будем пользоваться VirtualAlloc для буфера char* Buf = (char*) VirtualAlloc(NULL, BUFSIZE,

MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

// Открытие заданного файла для чтения

HANDLE hSrc = CreateFile(szSrc, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);

// Создание файла для записи

HANDLE hTgt = CreateFile(szTgt, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL);

// Если файлы открыты

if ((hSrc != INVALID_HANDLE_VALUE) && (hTgt != INVALID_HANDLE_VALUE))

{

79

//результат чтения из файла

DWORD dwResult = 0;

//читаем из исходного файла

if (ReadFile(hSrc, Buf, BUFSIZE, &dwResult, NULL))

{

// устанавливаем длину целевого файла.

SetFilePointer(hTgt, 1024+dwResult, NULL, FILE_BEGIN);

SetEndOfFile(hTgt);

//Будем писать не с 0, а с позиции 1024 в файле

SetFilePointer(hTgt, 1024, NULL, FILE_BEGIN);

//Записываем число байт, считанных ReadFile

if (!(WriteFile(hTgt, Buf, dwResult, &dwResult, NULL)))

printf("Ошибка! записи"); } else printf("Ошибка");

//Закрываем файлы

CloseHandle(hSrc);

CloseHandle(hTgt);

//Освобождаем буфер

VirtualFree(Buf, 0, MEM_RELEASE);

}else printf("Ошибка: один из файлов не открыт");

}

Асинхронный ввод-вывод

При асинхронном запросе ввода-вывода поток, выдавший запрос поток не блокируется до окончания выполнения, а продолжает выполнять другие задачи. В какой-то момент времени поток (или другой поток) достигнет такой точке в коде, где ему понадобится результат ввода-вывода, – т.е. он должен синхронизироваться с операцией ввода-вывода. На данный момент это решается рядом способов, которые рассмотрены ниже.

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

80