Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебник Емельянов.doc
Скачиваний:
12
Добавлен:
03.11.2018
Размер:
3.25 Mб
Скачать

С файлами

Иногда требуются стандартные функции работы с файлами Windows, тем более что возможности в них расширены. Каждый файл в Windows опи­сывается не переменной, а дескриптором (THandle, можно описывать Car­dinal), который представляет собой 32-разрядную величину, идентифици­рующую файл в операционной системе. Открывается файл при помощи сле­дующей функции:

function CreateFileA(lpFileName: PAnsiChar;

dwDesiredAccess, dwShareMode: DWORD;

lpSecurityAttributes: PSecurityAttributes;

dwCreationDisposition, dwFlagsAndAttributes: DWORD;

hTemplatePile: THandle): THandle; stdcall;.

Такое большое количество параметров функции связано с тем, что сгеateFileA используется для открытия файлов на диске, устройств, каналов, портов и, вообще, любых источников ввода и вывода. Рассмотрим назначе­ние параметров.

Здесь ipFileName - имя открываемого объекта; dwDesiredAccess -способ доступа к объекту (может иметь значение generic_read-для чте­ния, generic_write - для записи или комбинация этих значений). Если dwDesiredAccess =0, то можно получить атрибуты файла без фактическо­го его открытия. Параметр dwShareMode открывает режим совместного с другими программами доступа (о - совместный доступ запрещен;

FILE_SHARE_READ – для чтения; FILE_SHARE_WRITE – Для записи; Комбинация этих значений - полный доступ). В рассматриваемой функции можно задавать атрибуты защиты объекта - lpSecurityAttributes (если равно nil, то устанавливаются атрибуты по умолчанию). Следующий параметр dwCreationDisposition отвечает за способ открытия объекта (create_new - создается новый объект, если таковой существует, иначе воз­вращается Ошибка ERROR_ALREADY_EXISTS; CREATE_ALWAYS - создается

новый объект, если таковой существует, или, если возможно, перезаписыва-202

ется, иначе выдается ошибка; open_exi sting - открывает существующий объект или, если таковой не найден, возвращается ошибка; open_always -открывает существующий объект, если таковой не найден, он создается). Набор атрибутов (скрытый, системный, сжатый) и флагов для открытия объ­екта задается параметром dwFlagsAndAttributes. Последний параметр hTemplateFile задает файл-шаблон, атрибуты которого используются для открытия объекта.

Функция возвращает дескриптор открытого объекта (некоторое число). Если открыть объект невозможно, то возвращается код ошибки invalid_handle_valoe. Более полные сведения об ошибке можно полу­чить, вызвав функцию GetLastError.

Закрывается объект функцией function CloseHandle(hObject: THandle): BOOL; stdcall;.

Для чтения и записи данных используются следующие функции:

function ReadFile(hFile: THandle; var Buffer; nNumberOf-BytesToRead: DWORD; var lpNumberOfBytesRead: DWORD; lpOver-lapped: POverlapped): BOOL; stdcall;

function WriteFile(hFile: THandle; const Buffer; nNum-berOfBytesToWrite: DWORD; var lpNumberOfBytesWritten: DWORD; lpOverlapped: POverlapped): BOOL; stdcall;

Здесь nNumberOfBytesToRead и nNumberOfBytesToWrite - количест­во байт, которое нужно прочитать или записать; lpNumberOfBytesRead и lpNumberOfBytesWritten - количество байт, которое фактически прочи­тано или записано. Параметр lpOverlapped - указатель на некоторый деск­риптор структуры (типа TOverlapped) события отложенного ввода или вы­вода, например, для каких-то относительно "медленных" устройств. Созда­ется событие следующей функцией: function CreateEventA( lpEven-tAttributes: PSecurityAttributes; bManualReset, blnitialState :BOOL; lpName: PAnsiChar): THandle; stdcall;. Эта функция как раз и возвращает указанный выше дескриптор, на который ссылается параметр lpOverlapped. С помощью данного события автоматически включается отложенный ввод или вывод. Время в миллисекундах (параметр dwMilli-seconds), которое разрешается ожидать при отложенном вводе или выводе, указывается в функции function WaitForSingleObject(hHandle : THandle; dwMilliseconds: DWORD): DWORD; stdcall;, которая преры­вает отложенную операцию чтения или записи. Можно задать бесконечный интервал infinite.

Функция createFileA полезна при работе с портами, например, сле­дующая программа позволяет успешно открыть порт СОМ1 и выдать мини­мальные сведения о подключенном к этому порту модеме.

procedure TForm1.Button1Click(Sender: TObject);

203

var CommPort : string;

hDev : THandle;

ModemStat : DWord;

begin

CommPort := 'CCM1';

hDev := CreateFile(PChar(CommPort), GENERIC_READ,O,nil,

OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if hDev = INVALID_HANDLE_VALUE then begin

ShowMessage('Ошибка открытия порта '+ CommPort); exit;

end;

if GetCommModemStatus(hDev,ModemStat)ofalse then begin

if ModemStat and MS_CTS_ON <> 0 then ShowMessage(

'Управление CTS (clear-to-send) в порядке.');

if ModemStat and MS_DSR_ON <>0 then ShowMessage(

'Управление DSR (data-set-ready) в порядке.'); if ModemStat and MS_RIN6_ON <> Othen ShowMessage(

'Управление ring indicator в порядке.');

if ModemStat and MS_RLSD_ON <> 0 then ShowMessage( 'Управление RLSD (receive-line-signal-detect) в порядке.'); end;

CloseHandle(hDev); end; .

Еще один вариант использования рассматриваемой функции Windows API можно привести, когда требуется посекторное чтение, например, в дис­ководе А:.

Const SectorSize=512; Var Buffer:Pointer;

FUNCTION TForm1.ReadSector(Head,Track,Sector:integer; Buffer:pointer):boolean;

var

hDev:THandle; DevName:string; nb:cardinal;

begin

DevName: ='\\.\A: ';

hDev:=CreateFile(pChar(DevName),GENERIC_READ,

FILE_SHARE_READ or FILE_SHARE_WRITE,nil,

OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0);

if hDev=INVALID_HANDLE_VALDE then begin

Result:=false;

Exp­end;

SetFilePointer(hDev,(Sector-1)*SectorSize,nil,FILE_BEGIN); Result:=ReadFile(hDev,Buffer,SectorSize,nb,nil)

and (nb=SectorSize);

204

CloseHandle(hDev);

end;

В данном примере для позиционирования файлового указателя применя­ется еще одна функция Windows API setFilePointer, объявленная сле­дующим образом: function SetFilePointer(hFile: THandle; lDis-tanceToMove: Longint; lpDistanceToMoveHigh: Pointer; dwMoveMethod: DWORD): DWORD; stdcall;.

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

Далее рассматривается небольшой пример, чтобы продемонстрировать указанные выше функции в работе.

ПРИМЕР ПРИЛОЖЕНИЯ 25

Пусть имеется текстовый файл, созданный по правилам Delphi. Требует­ся открыть этот файл указанной выше функцией Windows API и прочитать его содержимое. При выполнении этого примера встретятся некоторые трудности из-за того, что придется читать файл как совокупность байтов, а потом эти байты пытаться интерпретировать. Вариант решения примера приводится на рис. 61.

Рис.61 Ниже приводится текст программы.

unit OMSfile; interface

205

uses Windows, Messages, SysUtils, Variants, Classes,

Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons type

TForm1 = class(TForm) Button1: TButton;

Memo1: TMemo;

BitBtnl: TBitBtn;

Memo2: TMemo;

Label1: TLabel;

procedure Button1Click(Sender: TObject); procedure FormDeactivate(Sender: TObject); public

hDev:THandle; end;

var Form1: TForm1; Buffer:pointer; FilSize:cardinal; implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject); type buf=array of byte; var FilName:string; nb:cardinal; i,r:byte; F:File;

sNumber:string [3]; begin

FilName: ='InpFil.txt' ; Buffer := Nil; FilSize:=0;

AssignFile(F, FilName);

System.Reset(F, 1);

{$1+}

if IOResult<>O then begin

memo1.Lines.Add('Ошибка открытия файла');

Exit; End;

FilSize := FileSize(F); closeFILE(F);

Memo1.Lines.Add('FilSize= '+inttostr(FilSize)); memo2.Lines.LoadFromFile(FilName); hDev:=CreateFileA(pChar(FilName),GENERIC_READ,

FILE_SHARE_READ or FILE_SHARE_WRITE,nil,

OPEN_EXISTING, FILE_ATTRIBUTE_NOPMAL,0);

if hDev=INVALID_HANDLE_VALUE then begin

memo1.Lines.Add(' Ошибка открытия файла Windows');

Exit;

end; try

Getmem(Buffer, FilSize) ;

ReadFile{hDev,Buffer,FilSize,nb,nil);

Memo1.Lines.Add('Прочитано байтов'+inttostr(nb)); Memo1.Lines.Add('Прочитаны числа1); sNumber:='';

FOR I:=0 TO FilSize DO BEGIN r:=buf(@buffer)[I]; if chr(r) in ['0'..'9'] then

sNumber:=sNumber+chr(r) else begin

if length(sNumber)>0 then Memo1.Lines.Add(sNumber); sNumber:=''; end; END; finally

CloseHandle(hDev); end; end;

procedure TForm1.FormDeactivate(Sender: TObject); begin

FreeMem(Buffer,FilSize); end; end.

В данной программе вначале определяется количество байт в исходном файле, которое включает в себя все символы, содержащиеся в файле, в том числе и разделители, т.е. отдельные цифры чисел, пробелы, #13, #10. Далее этот файл открывается как файл Windows. Байты считываются в переменную Buffer и с помощью преобразования типа Pointer в тип Array of byte восстанавливаются в исходные числа. В примере показан один из вариантов работы с типом Pointer.

ИСПОЛЬЗОВАНИЕ ОТОБРАЖАЕМЫХ ФАЙЛОВ

В Windows под памятью подразумевается не только оперативная память (ОЗУ), но также и память, резервируемая операционной системой на жест­ком диске. Этот вид памяти называется виртуальной памятью. Посредст­вом страничной системы (paging system) подкачки в такую память на же­стком диске отображаются код и данные. По мере необходимости требуе­мый фрагмент виртуальной памяти переносится из страничного файла в ОЗУ и, таким образом, становится доступным для выполнения. Данный механизм отображения можно применить и для любого другого файла, сделав его со­держимое частью адресного пространства.

207

Для выделения фрагмента виртуальной памяти должен быть создан спе­циальный системный объект , называемый отображаемым файлом. Отобра­жаемый в адресное пространство дескриптор объекта создается операцион­ной системой при вызове следующей функции Windows API: function CreateFileMappingA(hFile: THandle; lpFileMappingAttributes: PSecurityAttributes; flProtect, dwMaximumSizeHigh, dwMaximum-SizeLow:DWORD; lpName: PAnsiChar): THandle; stdcall;.

Первый параметр соответствует дескриптору открытого при помощи функции createFile файла. Второй параметр является указателем на структуру с данными по защите файла. Посредством параметра f lProtect указывается тип доступа к файлу, например, page_readwritk. С помощью параметров dwMaximumSizeHigh, dwMaximumSizeLow задается выделяемое пространство виртуальной памяти. Если отображается весь файл, то их зна­чения можно задать равными нулю (при условии, что файл намного меньше 4 Гбайт). Последний параметр представляет собой имя объекта файлового отображения (применяется при вызовах из разных, но одновременно исполь­зующих созданный объект, программ).

Следующий этап построения отображения - спроецировать данные фай­ла в адресное пространство. Этой цели служит следующая функция: func­tion MapViewOfFile(hFileMappingObject: THandle; dwDesiredAc-cess: DWORD; dwFileOffsetHigh, dwFileOffsetLow, dwNumberOf-BytesToMap: DWORD): Pointer; stdcall;.

Первый параметр является дескриптором созданного объекта файлового отображения. С помощью второго параметра определяется режим доступа к объекту (file_map_write, filb_map_read, file_map_all_access). По­средством третьего и четвертого параметров задается смещение отображае­мого участка относительно начала файла (чаще всего оба параметра равны нулю). Пятый параметр определяет количество байт данных файлового ото­бражения - если равен нулю, то отображаются все данные, выделенные при этом функцией CreateFileMappingA.

Функция MapViewOfFile вернет начальный адрес (тип возвращаемого результата - Pointer) данных в памяти. Далее можно работать с исходным файлом как с обычной памятью.

По окончании работы с отображаемым в памяти файлом необходимо вернуть занятое адресное пространство, используя функцию function DnmapViewOfFile(lpBaseAddress: Pointer): BOOL; stdcall;, где lpBaseAddress - используемый выше указатель. Последняя операция, ко­торую надо выполнить, - закрыть полученный выше дескриптор. Эта опера­ция выполняется путем вызова еще одной функции Windows API: function CloseHandle(hObject: THandle): BOOL; stdcall;.