Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Программирование. Процедурное программирование. Учебное пособие
.pdf
Основные возможности процедурного программирования при работе с комбинированными данными…
procedure WriteLn(var F: TextFile; P1; Pn);
Процедура, аналогичная процедуре Write, которая после записи значений дописывает в файл спецсимволы перевода строки.
procedure CloseFile(var F: TextFile);
Процедура, завершающая работу с открытым файлом, в результате вызова которой содержимое ассоциированного файла на диске обновляется до последней
версии и сохраняется.
function FileExists(FileName: string): Boolean;
Функция, которая проверяет, существует ли файл с именем FileName, и возвращает соответствующее значение логического типа.
Замечание. В программе определены специальные текстовые файлы – стандартные файлы ввода (Input) и вывода (Output). По умолчанию они назначены на клавиатуру и монитор. Поэтому, если
в процедурах Read/ReadLn и Write/WriteLn файловые переменные не
указаны явно, то используются стандартные файлы.
Замечание. В случае если происходит попытка открыть на чтение несуществующий файл, либо содержимое файла по формату не
соответствует выполняемой операции чтения (например, происходит чтение числа, а следующим символом в файле находится буквенный символ), либо возникает какая-либо другая ошибочная ситуация при работе с файлом, то в коде программы возникает исключение и программа прекращает работу.
В языке программирования Delphi поддержка типизованных файлов
реализована следующим набором процедур и функций.
procedure AssignFile(var F: file; FileName: string);
Происходит связывание файловой переменной F с именем файла FileName на
диске.
Примеры применения процедуры AssignFile
AssignFile(F, 'numbers.dat');
AssignFile(Catalog,'C:\MyFiles\catalog.dat');
Замечание. Если файл хранится в одной директории с проектом,
то достаточно указать его короткое имя (при стандартных на-
61

Глава 2
стройках сборщика проекта Delphi). Если файл хранится вне проекта, то необходимо указывать его полное имя, начиная с диска
размещения. Для учебных задач рекомендуется все файлы хранить
вместе с проектом. Так будет проще переносить проект с одного
компьютера на другой, при этом не будет необходимости исправлять имя файла в программе.
Для начала работы с файлом он должен быть открыт. Для этого при-
меняются операции Reset или Rewrite.
procedure Reset(var F: file);
Оператором Reset открывается существующий файл, связанный с файловой переменной F.
procedure Rewrite(var F: file);
Оператор Rewrite создает и открывает новые файлы. При открытии существующего файла при помощи оператора Rewrite его содержимое будет стерто.
В отличие от текстовых типизированные файлы допускают чередо-
вание операций записи и чтения независимо от того, каким оператором
(Reset или Rewrite) он был открыт.
Далее перечислены основные процедуры и функции для работы
с типизированными файлами.
function FileExists(FileName: string): Boolean;
Функция возвращает True, если файл с указанным именем существует на диске.
procedure CloseFile(var F: file);
Производится закрытие файла, связанного с файловой переменной F.
procedure Read(var F: file; V1, V2,...,Vn);
Осуществляется чтение из файла, связанного с файловой переменной F, указан-
ного списка переменных V1, V2,..., Vn. Все перечисленные переменные должны
иметь тип компонент файла.
procedure Write(var F: file; V1, V2,...,Vn);
Осуществляется запись в файл, связанного с файловой переменной F, указанного
списка переменных V1, V2, ..., Vn. Все перечисленные переменные должны
иметь тип компонент файла.
procedure FileSize(var F: file):Integer;
Функция возвращает общее количество записей в файле.
62

Основные возможности процедурного программирования при работе с комбинированными данными…
Все элементы типизированного файла одного типа, а значит, и одно-
го размера. Благодаря этому возможен произвольный доступ к элементам
типизированного файла.
Произвольный доступ к элементам файла осуществляется операто-
ром Seek. Текущее положение указателя файла возвращается функцией
FilePos.
procedure Seek(var F: file; k: Integer);
Процедура устанавливает указатель файла на элемент с указанным номером k,
нумерация начинается с 0.
procedure FilePos(var F: file):Integer;
Функция возвращает текущее положение указателя.
Примеры применения процедуры Seek
Seek(F, 0); // Перемещение указателя на начало файла
Seek(F, FileSize(F)); // Перемещение указателя в конец файла
Как и для текстовых файлов, ситуация «конец файла» диагностиру-
ется функцией EoF (файловая переменная).
Пример программы № 9
В текстовом файле «book.txt» записан некоторый текст. Подсчи-
тать число слов в нем.
Разработка программы
Воспользуемся кодом подсчета количества слов в строке, разрабо-
танным в примере программы № 8, и оформим его в виде функции
CountWords, получающей на вход строку и возвращающей число слов
в ней в качестве результата.
По заданию требуется открыть файл на чтение, построчно его считать
и просуммировать количество слов по всем строкам. Оформим этот алгоритм в виде функции CountWordsInFile, принимающей в параметре имя
входного текстового файла и возвращающей общее число слов в нем в качестве результата. Перед началом чтения данных из файла, как и в предыдущем примере, потребуется вызвать процедуры AssignFile и Reset. Чтение
строк из файла организуем в виде цикла с условием проверки достижения
конца файла not EoF(F). На каждой итерации цикла будем читать строку из
файла и помещать ее в переменную S, вычислять при помощи функции
CountWords количество слов в ней и накапливать результат в переменной
Result.
63

Глава 2
Текст программы полностью приведен в листинге 9.
Листинг 9. Пример программы № 9
program Example9;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows;
const
Separators = [',', '.', '!', '?', '-', ' '];
function CountWords(S: string): Integer;
var CharType: Boolean;
I: Integer;
begin
S := ' ' + S + ' ';
Result := 0;
CharType := true;
for I := 1 to Length(S) do
if (S[I] in Separators) <> CharType then
begin
if CharType then
Result := Result + 1;
CharType := not CharType;
end;
end;
function CountWordsInFile(FileName: string): Integer;
var F: TextFile;
S: string;
begin
Result := 0;
AssignFile(F, FileName);
Reset(F);
while not Eof(F) do
begin
ReadLn(F,S);
Result := Result + CountWords(S);
end;
CloseFile(F);
end;
begin
SetConsoleOutputCP(1251);
WriteLn('Количество слов = ', CountWordsInFile('book.txt'));
ReadLn;
end.
64

Основные возможности процедурного программирования при работе с комбинированными данными…
Результат работы программы для текстового файла
Привет!
Как дела?
будет следующий:
Количество слов = 3
Создание типизированного файла
Одной из областей применения типизированных файлов является
хранение данных о наборе объектов, характеризующихся набором значений. Для этой цели используются типизированные файлы записей. Приведем пример процедуры CreateFile создания файла записей о мебели, характеризующейся полями: наименование предмета мебели, материал, цена.
Пример процедуры создания типизированного файла
type
// Запись - предмет мебели:
TFurniture = record
Name: string[20]; // Наименование
Material: string[50]; // Материал
Price: Real; // Цена
end;
TFurnitureFile = File of TFurniture; // Файл записей
// Процедура создания типизированного файла
procedure CreateFile(FileName: string);
var
F: TFurnitureFile;
Count, I: integer;
Item: TFurniture;
begin
AssignFile(F, FileName);
Rewrite(F); // Создание нового файла
Write(' Введите количество записей: ');
ReadLn(Count);
for I := 1 to Count do
begin
WriteLn(' Запись №', I);
Write(' Введите наименование: '); ReadLn(Item.Name);
Write(' Введите материал: '); ReadLn(Item.Material);
Write(' Введите цену: '); ReadLn(Item.Price);
65

Глава 2
Write(F, Item);
end;
CloseFile(F);
end;
Чтение данных из типизированного файла
После того как файл создан, он пригоден для обработки (например,
для просмотра). Обработка (просмотр) осуществляется строго последовательно, начиная с первой компоненты файла. При этом на каждом шаге
доступна лишь одна компонента файла.
Следующий пример демонстрирует просмотр ранее созданного файла.
Процедура вывода содержимого типизированного файла
// Процедура печати содержимого типизированного файла на экран
procedure ReadData(FileName: string);
var
FileData: TFurnitureFile;
Item: TFurniture;
begin
AssignFile(FileData, FileName);
Reset(FileData);
while not EoF(FileData) do
begin
Read(FileData,Item);
with Item do
begin
WriteLn(Name:20, Material:20, Price:10:2);
end;
end;
CloseFile(FileData);
end;
Контрольные вопросы и задания
1. Какие операции разрешены для записи в целом?
Как описывается файловая переменная для текстового файла, ти-
2.
пизированного файла?
Какие существуют способы открыть файл? В чем их отличие (для
3.
текстового файла, для типизированного файла)?
Чем отличаются текстовые файлы от файлов file of string?
4.
Перечислите действия, которые выполняет процедура Seek? Что
5.
возвращают функции FileSize и FilePos?
66

Основные возможности процедурного программирования при работе с комбинированными данными…
2.3. Расширенная работа с файлами.
Типизированные константы. Преобразование типов
Проверка существования файла
При работе с файлами в программе часто приходится открывать
файлы, существующие на диске. Предполагается, что эти файлы существуют и могут быть открыты. Однако бывают случаи, когда файл не существует или поврежден. Открыть такой файл не представляется возможным.
Далее приведен текст функции TestFile, проверяющей корректность
имени файла. Параметром функции является строка FileName (имя файла).
Функция возвращает логическое значение True, если нет ошибок при открытии файла; False, если имеется ошибка, например, файла с таким именем не существует на диске.
Проверка корректности имени файла
// Функция тестового открытия файла
function TestFile(FileName: string):boolean;
var
FileIn: TextFile;
begin
AssignFile(FileIn, FileName);
{$I-}
Reset(FileIn);
{$I+}
Result := IOResult <> 0;
if not Result then CloseFile(FileIn);
end;
В функции производится пробное открытие файла для чтения при
помощи функции Reset. Однако если файл не существуют на диске либо
его невозможно открыть, произойдет ошибка ввода/вывода, программа завершится и выведется сообщение об ошибке. Для возможности отслеживать ошибки ввода/вывода оператор Reset помещен в блок с выключенной
опцией проверки ввода/вывода {$I-}. Если происходит ошибка ввода/вывода и проверка ввода/вывода выключена, то все последующие операции ввода/вывода игнорируются, пока не будет сделано обращение
к функции IOResult, при котором очищается внутренний флаг ошибки.
Добавление записей в конец типизированного файла
Для добавления записей в файл используются следующие стандарт-
ные процедуры и функции:
67

Глава 2
procedure Seek(var F: file; k: Integer);
Эта процедура устанавливает указатель (курсор) файла на элемент с указанным
номером k.
procedure FilePos(var F: file):Integer;
Функция возвращает текущее положение файлового курсора.
В следующем примере представлена процедура добавления записи
в конец файла.
Процедура добавления записи в конец файла
procedure AddData(FileName: string);
var
Item: TFurniture;
F: TFurnitureFile
begin
Seek(F, FileSize(F)); {Установить указатель на последнюю
компоненту файла}
Write(' Введите наименование: '); ReadLn(Item.Name);
Write(' Введите материал: '); ReadLn(Item.Material);
Write(' Введите цену: '); ReadLn(Item.Price);
Write(F, Item);
end;
Замена записи в файле
Если известен номер заменяемой записи, то можно ее заменить, ис-
пользуя оператор Seek. В случае когда известно содержимое записи, используется последовательный поиск записи в файле. Ниже представлена
процедура Swap перестановки двух записей в типизированном файле.
Процедура обмена местами двух записей в файле
procedure SwapData(var F: TFurnitureFile; Index1, Index2:
Integer);
var
Item1, Item2: TFurniture;
begin
// Считывается запись на позиции Index1
Seek(F, Index1); Read(F, Item1);
// Считывается запись на позиции Index2
Seek(F, Index2); Read(F, Item2);
// На позиции Index2 записывается первая запись
Seek(F, Index2); Write(F, Item1);
// На позиции Index1 записывается вторая запись
Seek(F, Index1); Write(F, Item2);
end;
68

Основные возможности процедурного программирования при работе с комбинированными данными…
Сортировка записей в файле
Далее приведена рекурсивная процедура Sort сортировки записей
в типизированном файле, основанная на сортировке выбором. В этом случае в файле последовательным просмотром ищется запись с наименьшим
значением поля Price и переставляется в начало неотсортированной части
файла (первая запись и минимальная меняются местами). После этого процесс сортировки повторяется в неотсортированной части файла.
Процедура сортировки записей в типизированном файле
procedure Sort(var F: TFurnitureFile; I: Integer = 0);
var
Item, Item_1, Item_min: TFurniture;
Index, Index_min: Integer;
begin
// Устанавливаем указатель файла на запись с номером I
Seek(F, I);
Read(F, Item_1);
{Далее в файле осуществляется поиск записи с наименьшим
значением поля Price}
Item_min:=Item_1; Index_min:= I;
Index := I+1;
while not EoF(F) do
begin
Read(F,Item); // Считываем очередную запись
{Если поле Price текущей записи меньше поля Price
минимальной записи}
if Item.Price < Item_min.Price then
begin
// Переписываем минимальную запись и ее номер
Item_min:=Item;
Index_min:=index;
end;
Index := Index+1;
end;
{Если минимальная запись не совпадает с первоначальной,
то меняем записи местами}
if Index_min <> I then SwapData(F, Index_min, I);
{Если в файле остались неотсортированные записи,
то продолжаем рекурсивно сортировку}
if I < FileSize(F)-1 then Sort(F,I+1);
end;
Существуют и другие дополнительные возможности работы с фай-
лами. Например, определение эффективного буфера обмена данными
между оперативной и внешней памятью, введение дополнительных раз-
69

Глава 2
делителей между элементами текстовых файлов для обмена файловыми
данными и т. п.
Типизированные константы
В Delphi допускается использование типизированных констант.
В этом случае после имени константы через двоеточие указывается ее тип,
а затем через знак равенства – ее значение. Они описываются в разделе
объявления констант следующим образом:
<идентификатор> : <тип> = <значение>;
где <идентификатор> – идентификатор константы, <тип> – тип константы,
<значение> – значение константы.
Типизированные константы могут быть любых типов, кроме файлов.
В отличие от нетипизированных констант типизированные константы не
могут быть использованы при объявлениях границ типа-дипазона.
Обычно типизированные константы используются при работе со
сложноструктурированными данными (массивы, множества, записи).
При объявлении типизированной константы-массива ее начальные
значения перечисляются через запятую в круглых скобках. В случае объявления многомерной константы-массива множество констант, соответствующих каждому измерению, заключается в дополнительные круглые
скобки. При объявлении массива символов допускается задание символьной строки соответствующей длины.
Константы-массивы
type
TVector = array[1..5] of integer; {Одномерный массив}
TMatrix = array[1..5] of TVector; {Двумерный массив}
const
// Константа типа TVector
V: TVector = (1, 1, 1, 1, 1);
// Константа типа TMatrix:
U: TMatrix = ((1, 0, 0, 0, 0),
(0, 1, 0, 0, 0),
(0, 0, 1, 0, 0),
(0, 0, 0, 1, 0),
(0, 0, 0, 0, 1));
// Константа символьного массива
Letters: array[0..9] of Char = 'АЕЁИОУЫЭЮЯ';
end;
При объявлении константы записи ее значение представляет собой
список полей в виде последовательности вида: имя поля, двоеточие и кон-
70
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
