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

Демидов Основы программирования в примерах на языке ПАСЦАЛ 2010

.pdf
Скачиваний:
128
Добавлен:
16.08.2013
Размер:
1.28 Mб
Скачать

comma := false; // признак дробной части i:=1;

while i<length(s) and not comma do begin case s[i] of

'0'..'9': int := int*10 + ord(s[i])-ord('0'); '.': comma := true;

end;

i := i+1; end;

if comma then begin

for i:=length(s) downto comma+1 do frac := frac/10 + ord(s[i])-ord('0');

frac := frac/10; end;

r := int + frac;

if s[1] = '-' then r := -r; Evaluate := r;

end;

6. Реализовать алгоритм поиска подстроки в строке:

function Pos(sub, S: string): integer; var

i,j: integer;

ok, found: boolean; begin

Pos := 0; i:=1;

while (i<=length(s)) do begin

while s[i] <> sub[1] do i:=i+1; // ищем первый символ

// сравниваем остаток ok := true;

j:=1;

while (i+j-1<=length(s)) and (j<=length(sub)) do begin ok := ok and (s[i+j-1] = sub[j]);

j := j+1; end;

// если все символы совпали, то подстрока найдена found := ok and (j>length(sub));

if found then break; i := i+1;

end;

if found then Pos := i; end;

Данный алгоритм далёк от оптимального – информация о символах в подстроке и результаты предыдущих сравнений никак не

111

используются после увеличения i. Подобные алгоритмы называют алгоритмами «грубой силы и невежества» (ГСН, brute force algorithm). Существуют гораздо более эффективные алгоритмы, например алгоритм Кнута–Морриса–Пратта или алгоритм Бойера– Мура.

112

Глава 11. Текстовые файлы

Понятие файла

Файл, записанный на какой-либо электронный носитель, представляет собой обособленный поименованный набор данных произвольной длины. В таком представлении файл статичен. Основное назначение таких файлов состоит в хранении информации любого рода от неструктурированных данных до исполняемых программ и библиотек. Для этого, как правило, применяются энергонезависимые носители, такие как гибкие и жесткие магнитные диски, ленты, оптические диски, flash-накопители и т.п. Для указания местоположения файла на носителе используют либо абсолютный путь, либо путь относительно текущего каталога. Форма записи пути к файлу различается в зависимости от операционной системы. Для MS Windows путь имеет вид [<диск>:\]{<каталог>\}<имя файла>[.<расширение>]. Здесь <>{}[] – метасимволы, [] – необязательная конструкция, {} – конструкция, повторяющаяся 0 и более раз. Например:

coprime.pas

– файл в текущем каталоге

bin\coprime.exe

– относительный путь к файлу

D:\winnt\paint.exe

– абсолютный путь к файлу

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

Вообще говоря, понятие файла является абстракцией, лежащей в основе системы ввода-вывода. Ввод – процесс передачи данных в оперативную память извне (клавиатура, носители данных, порты ввода-вывода), а вывод – процесс передачи данных из оперативной памяти во внешнюю среду (дисплей, носители данных, порты вво- да-вывода). Каждый канал передачи данных между устройством и оперативной памятью имеет свое уникальное имя, а для осуществления операций ввода-вывода используется тот же механизм работы с файлами. Например, устройствам соответствуют такие имена файлов, как COM1, COM2, PRN, CON, NUL.

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

113

веком является тем критерием, по которому файлы делят на два класса:

текстовые файлы;

бинарные файлы.

Текстовый файл представляет собой последовательность строк, разделенную маркерами конца строки (символами возврата каретки #13 и перевода строки #10). При редактировании текстового файла эти символы вставляются в файл при нажатии клавиши Enter. Сами по себе они никак не отображаются на экране, а служат для визуального разделения строк. Каждая строка в свою очередь является последовательностью привычных печатных символов: буквенноцифровые символы, знаки пунктуации, математические символы, специальные символы.

Примеры текстовых файлов: txt-файлы, файлы с исходными текстами программ (*.pas, *.c, *.hpp и др.), пакетные исполняемые файлы (*.bat), интернет-страницы, скрипты, размеченные файлы

(*.asp, *.vb, *.txt, *.htm, *.xml, *.xslt, *.xsd) и любые другие файлы,

читаемые человеком в простейших текстовых редакторах. Бинарный файл представляет собой произвольную последова-

тельность байт. При открытии бинарного файла в текстовом редакторе содержимое каждого байта будет отображаться в виде соответствующего ему символа в ASCII-таблице.

Бинарные файлы в свою очередь делятся на два подкласса:

типизированные файлы;

нетипизированные файлы.

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

Нетипизированный файл – произвольная последовательность байт. Таким образом, нетипизированным файлом можно считать любой файл, который нельзя рассматривать как текстовый или типизированный. Если не представляется возможным выяснить, можно ли файл рассматривать как текстовый или типизированный или же это вообще не важно, то файл также следует считать нетипизированным.

Эти классы определяют лишь способ интерпретации внутренней структуры файлов программистом, поэтому один и тот же файл

114

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

Буферизация операций ввода-вывода

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

В Паскале по умолчанию буфер для работы с файлами имеет размер 128 байт. Однако существует возможность изменить размер буфера до начала работы с файлом.

Механизм работы с файлами в языке Паскаль

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

Общую схему работы с файлом можно представить следующим образом:

1)объявление файловой переменной;

2)связывание файловой переменной с физическим файлом;

115

3)открытие файла;

4)выполнение операций ввода-вывода;

5)закрытие файла.

Для работы с текстовыми файлами следует объявлять файловые переменные типа TextFile. Например:

var

f,g: Text; // в Delphi тип TextFile

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

Общие процедуры и функции работы с файлами

Рассмотрим программу, распечатывающую на экране содержимое текстового файла:

var

f: Text;

path, s: string; begin

write('Enter file path: ');

readln(path);

// связывание файла с переменной

assign(f, path);

reset(f);

// открытие файла на чтение

// пока не достигнут конец файла while not EOF(f) do begin

readln(f, s);

// чтение из файла

writeln(s);

 

end;

// закрытие файла

close(f);

end.

 

В этой программе используется ряд стандартных подпрограмм работы с файлами:

procedure Assign(var f; filename: string) – связывает файловую переменную f с физическим файлом, путь к которому указан в строке filename. При этом существование файла не требуется.

procedure Reset(var f [: File; RecSize: Word ]) – открывает су-

ществующий физический файл, на чтение-запись. Если файл не существует, то возникает ошибка ввода-вывода. Если файл был открыт ранее, то он закрывается и открывается заново. Текстовые файлы открываются только на чтение. Параметр RecSize передает-

116

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

procedure Rewrite(var f [: File; RecSize: Word ]) – открывает на запись новый файл, связанный с переменной f. Если файл существовал ранее, то он стирается, и создается новый файл. Если f была связана с пустым путем Assign(F,''), то после вызова Rewrite f будет связана со стандартным файлом вывода. Текстовые файлы открываются только на запись. Параметр RecSize передается только для нетипизированных файлов и указывает размер блока для операций ввода-вывода.

function EOF(var f): boolean – возвращает истину, если при чтении достигнут конец файла, и ложь – в противном случае. Сокращение EOF происходит от англ. End Of File (конец файла).

procedure Сlose(var f) – закрывает открытый файл, связанный с переменной f. Если файл был открыт для записи, то перед закрытием в файл дописывается содержимое буфера записи.

procedure Erase(var f) – уничтожает физический файл, связанный с переменной f. До вызова Erase файл должен быть закрыт.

procedure Rename(var f; newname : string) – переименовывает физический файл, связанный с переменной f.

Организация доступа к данным в файле. Курсор

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

Существуют два режима доступа к содержимому файла:

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

прямой.

Схема последовательного доступа такова:

1)при открытии файла курсор позиционируется на первом символе файла;

2)в ходе операций чтения последовательно считываются участки файла, пока не будет достигнут конец файла.

117

При этом курсор каждый раз позиционируется на символе, следующим за считанным участком.

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

Схема прямого доступа:

1)при открытии файла курсор позиционируется на первом символе файла;

2)курсор перемещается на нужный участок файла;

3)считывается нужный участок.

Таким образом, перемещая курсор в любом направлении, можно считывать информацию в любом порядке. Массивы являются примером структуры данных с прямым доступом (по индексу).

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

Чтение и запись текстовых файлов

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

procedure Read( [ var F: Text; ] V1 [, V2,...,Vn ] ) – считывает из файла данные в переданные переменные в порядке их следования. Курсор позиционируется на символ, следующий за последним считанным символом. Считываемые переменные могут иметь различные типы, но типы должны быть простыми, например string, char, integer, real, за исключением boolean. Не допустимы сложные типы (массивы, записи, файлы). При чтении осуществляется приведение очередной считанной цепочки символов к типу фактического параметра.

procedure Readln([ var F: Text; ] V1 [, V2, ...,Vn ]) – аналогично

Read, но после чтения курсор позиционируется в начало следующей строки.

Для записи в файл используются процедуры:

procedure Write( [var F: Text; ] P1 [ , P2,..., Pn] ) – записывает в файл содержимое фактических параметров. При этом осуществляется преобразование типов к строковому. Фактические параметры также могут иметь различные простые типы, включая boolean. Сложные типы данных недопустимы.

118

procedure Writeln([ var F: Text; ] P1 [, P2, ...,Pn ]) – аналогично

Write, но после записи в файл помещается маркер конца строки

(#13#10).

Значения сложных типов можно вводить и выводить в текстовый файл только поэлементно. Например:

var

f: Text;

a: array[1..200] of integer; i: integer;

begin

write('Enter file path: '); readln(path);

assign(f, path);

rewrite(f); // открытие файла на запись for i:=1 to 200 do

writeln(f, a[i]);

// запись элементов в столбик

close(f);

// закрытие файла

end.

 

Видно, что для операций чтения-записи применяются одноименные процедуры Read и Write, используемые для ввода значений с клавиатуры и вывода на экран. Как уже говорилось, для работы с этими устройствами используется тот же файловый механизм. Существуют две системные переменные: INPUT – файловая переменная, связанная со стандартным вводом операционной системы (клавиатурой), и OUTPUT – файловая переменная, связанная со стандартным выводом операционной системы (экраном). Для программы эти файлы всегда открыты (INPUT – на чтение, OUTPUT – на запись), и в явном виде их нельзя открывать и закрывать.

Так, Read(x) равносильно Read(INPUT, x), а Write(x) равносильно Write(OUTPUT, x).

Другие стандартные подпрограммы для работы только с текстовыми файлами.

procedure Append(var f: Text) – открывает на запись физиче-

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

procedure Flush(var f: Text) – сброс содержимого буфера записи в файл, открытый процедурой rewrite или append. Процедура

119

используется для досрочной записи в файл независимо от уровня заполнения буфера.

procedure SetTextBuf(var F: Text; var Buf [ ; Size: Integer] )

замещение буфера, выделяемого по умолчанию, буфером Buf размером Size.

function SeekEOF(var f: Text): boolean – сдвигает курсор отно-

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

function SeekEOLN(var f: Text): boolean – сдвигает курсор от-

носительно текущей позиции до следующего символа, отличного от пробела, в этой же строке. Если при этом достигнут конец строки или файла, то возвращается истина, иначе возвращается ложь. Сокращение EOLN происходит от англ. End Of LiNe (конец строки).

Обработка ошибок ввода-вывода

Ошибки ввода-вывода вызывают аварийную остановку программы. Для того чтобы программа была более универсальной и продолжала работу в любых случаях, существует возможность обработки ошибок ввода-вывода внутри программы. Этим поведением управляет директива компилятора $I. Вообще, директивы компилятора размещаются в тексте программы внутри комментария {}. Для включения режима автоматической обработки ошибок следует записать {$I+}, для отключения – {$I-}. Область действия директивы простирается с момента её появления в программе до конца программы или до отменяющей её директивы. По умолчанию опция включена.

Для ручного анализа ошибок ввода-вывода необходимо отключить опцию $I и использовать стандартную системную функцию

IOResult:

function IOResult: integer – возвращает результат последней операции ввода-вывода. При успешном завершении операции вво- да-вывода возвращается 0, а в случае ошибки – ненулевой код ошибки.

Если при отключенной опции $I происходит ошибка, то все последующие операции ввода-вывода игнорируются до первого обращения к функции IOResult. После вызова функции IOResult

120

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