Листинг. Версия программы NTCAT, использующая традиционный файловый ввод/вывод




Лабораторная работа №5

Файловый ввод/вывод

 

Цель работы: Ознакомиться с основными способами ввода/вывода с использованием системных вызовов Windows 2000, в том числе с асинхронным вводом/выводом.

 

Зачем нужен асинхронный ввод/вывод? Асинхронный ввод/вывод — это механизм, позволяющий программе осуществлять обмен данными с каким-либо устройством ввода/вывода и одновременно с этим выполнять какую-либо другую полезную работу.

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

Обзор файлового ввода/вывода. Обычно, если вы хотите открыть файл, вы используете один из стандартных вызовов библиотеки C++ (такой как, например, fopen). В большинстве языков программирования предусмотрены достаточно удобные высокоуровневые средства работы с файлами. Однако в некоторых ситуациях требуется открыть файл и работать с ним на уровне операционной системы, не используя высокоуровневые функции. Например, прямое обращение к операционной системе может потребоваться в случае, если вы намерены использовать асинхронный ввод/вывод. Системный вызов, с помощью которого осуществляется открытие файла, называется CreateFile. На самом деле название этого вызова (в переводе на русский СreateFile — «создать файл») плохо отражает функции, которые он выполняет. Взависимости от флагов, которые вы передаете этому вызову, он может либо действительно создать новый файл, либо открыть уже существующий. Лучшим названием было бы не CreateFile, a CreateFileHandle — «создать дескриптор файла».

 

Рассмотрим консольную программу, которая эмулирует работу утилиты cat операционной системы Unix. В Unix утилита cat принимает в качестве аргумента командной строки список имен файлов и копирует содержимое этих файлов один за другим в стандартный поток вывода. Таким образом, при помощи этой утилиты можно объединить несколько файлов в один или отобразить содержимое файлов на экране консоли.

Утилита cat — это классический пример программы, которую можно написать с использованием стандартных функций STDIO или потоков ввода/вывода C++. В листинге (см. ниже) приводится исходный код, использующий для этой цели системные вызовы ввода/вывода Windows.

Листинг NTCAT содержит две реализации команды cat (выбор осуществляется при помощи оператора #if). Один метод предусматривает использование вызовов getc и putchar. Другой основан на функциях fread и fwrite, которые осуществляют чтение блоками по 4 Кбайт (блоки именно такого размера использует менеджер виртуальной памяти).

 

 

Задание:

1) ознакомиться с примером программы NTCAT, использующей традиционный ввод/вывод (см. описание ниже);

2) перестроить функцию docat программы NTCAT таким образом, чтобы использовать системные вызовы ReadFile, WriteFile. Вызов CreateFile открывает файл для чтения. После этого вызов GetStdHandle возвращает дескриптор стандартного вывода. Затем при помощи вызовов ReadFile и WriteFile блоками по 4 Кбайт происходит передача содержимого файла с жесткого диска в стандартный поток вывода. Чтобы закрыть файл используется CloseHandle;

3) реализовать функцию docat программы NTCAT таким образом, чтобы использовать механизм отображения файлов на оперативную память. Чтобы воспользоваться этим механизмом, откройте файл при помощи вызова CreateFile, а затем передайте дескриптор файла вызову CreateFileMapping. При этом будет создан объект отображения файла на память. После этого обратитесь к функции MapViewOfFile, которая возвратит вам указатель на содержимое файла, например char *. Для вывода из памяти на консоль используйте вызов cout.write. Когда работа с файлом завершена, необходимо обратиться к вызову UnmapViewOfFile, после чего дважды вызвать CloseHandle, чтобы закрыть объект отображения файла и закрыть дескриптор файла;

4) ознакомиться с реализацией программы, демонстрирующей асинхронный ввод/вывод на консоль с использованием отдельного программного потока (см. описание ниже);

5) переделать поток вывода таким образом, чтобы введенные в буфер символы выводились дважды;

6) переделать поток вывода таким образом, чтобы после вывода каждого символа поток вывода засыпал на одну-две секунды с помощью вызова sleep. Можно ли при этом продолжать вводить символы? Будут ли они выведены на консоль позже? Переполняется ли буфер ввода? Что необходимо сделать, чтобы избежать переполнения буфера?

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

Для всех программ использовать проект типа Win32 Console Application!

Утилита cat – это классический пример программы, которая написана с использованием стандартных функций STDIO и потоков ввода/вывода C++. Программа использует файловые операции для отображения на экране содержимого одного или нескольких файлов.

Листинг. Версия программы NTCAT, использующая традиционный файловый ввод/вывод

// NTCAT - Аналог утилиты cat для Win2000

// Обработка ошибок фактически отсутствует

// Любая ошибка прерывает выполнение программы,

// даже если программа работает с другими файлами

 

#include <windows.h>

#include <stdio.h>

 

// Для удобства использования MessageBox:

void MB(char* s)

{

MessageBox(NULL, s, NULL, MB_OK|MB_ICONSTOP);

}

 

// Эта программа выполняет основную работу:

void docat(char *fname)

{

FILE *f = fopen(fname, "r");

if (!f)

{

MB("Не могу открыть файл");

exit(1);

}

#if 1 // Выбор метода

int c;

while ((c=getc(f))!=EOF) putchar(c);

#else

char buf[4096];

int n;

while (!feof(f))

{

n = fread(buf,1,sizeof(buf),f);

if (n) fwrite(buf,1,n,stdout);

}

#endif

fclose(f);

}

 

void main(int argc, char * argv[]) {

if (argc==1)

{

MB("Используйте: ntcat FILENAME [FILENAME...]");

exit(9);

}

// Обработать все указанные файлы

while (--argc) docat(*++argv);

exit(0);

}

 

 

Проще всего реализовать асинхронный ввод/вывод с использованием отдельного программного потока. Для этого создается новый поток, в рамках этого потока выполняется операция ввода/вывода, а затем сообщается о результатах основной программе.

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



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-04-27 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: