Основы программирования — второй семестр 08-09; Михалкович С.С.; I часть
Содержание
- 1 Файлы
- 1.1 Введение
- 1.2 Классификация файлов
- 1.3 Понятие файловой переменной, файлового указателя
- 1.4 Буферизация в файлах
- 1.5 Подпрограммы для работы с закрытыми файлами
- 1.6 Типичные ошибки ввода-вывода при работе с файлами
- 1.7 Подпрограммы для работы с типизированными файлами
- 1.8 Подпрограммы для работы с текстовыми файлами
Файлы
Введение
Файл — именованная область на диске, содержащая некоторую информацию.
Преимущества:
- Хранят данные в промежутках между запусками программ.
- Размер данных в файле может существенно превышать оперативную память компьютера.
Классификация файлов
Файлы обычно классифицируют по двум признакам:
1. По типу компонент:
- текстовые;
- двоичные:
- типизированные;
- бестиповые.
2. По способу доступа:
- последовательный;
- произвольный.
<xh4>Текстовые файлы</xh4>
Тип text.
Состоят из строк переменной длины, в конце каждой из которых находится символ перехода на новую строку (#13#10 в Windows, #10 в Linux). В PascalABC.NET это константа NewLine.
Двоичные файлы: информация хранится в виде двоичного кода.
<xh4>Типизированные файлы</xh4> Тип file of <type>. Содержат данные фиксированного типа <type>.
<xh4>Бестиповые файлы</xh4> Тип file. Могут хранить данные различных типов.
В двоичных файлах информация хранится в том виде, как она хранится в оперативной памяти, а в текстовых числовая информация преобразуется к строковому виду и обратно, что занимает больше времени.
Файл называется
- файлом произвольного доступа, если можно перейти к его i-му элементу за время, не зависящее от размеров файла («за константное время»),
- файлом последовательного доступа, если переход к i-му элементу требует количество операций, пропорциональное i («требует линейного времени»).
Все файлы, содержащие элементы разного размера могут иметь только последовательный доступ к элементам. Таковыми являются:
- текстовые,
- бестиповые файлы.
Типизированные файлы имеют произвольный доступ.
Понятие файловой переменной, файлового указателя
Перед тем, как работать с информацией в файле, его надо открыть.
После этого можно выполнять операции чтения из файла и записи в файл.
По окончании работы его нужно закрыть.
Закрытый файл можно:
- переименовывать
- перемещать
- копировать
- удалять
С каждым открытым файлом связан так называемый файловый указатель, который указывает на текущую позицию в файле.
Файловый указатель создается при открытии файла, и, как правило, устанавливается на 1й элемент файла.
После каждой операции чтения или записи файловый указатель продвигается вперед на размер считанных элементов.
Паскаль-программа
var f: file of integer;
begin
Assign(f, 'a.dat');
{связывает файловую переменную f с файлом на диске 'a.dat'
(файл на диске может отсутствовать)}
//файл состоит из элементов (1, 2, 3)
Reset(f); //файловый указатель — на элемент "1"
var x: integer;
read(f, x); //x = 1
//файловый указатель — на элемент "2"
write(f, x + 4, 666); //теперь файл состоит из элементов (1, 5, 666)
//файловый указатель — за концом файла
{выполнить read(f, x) НЕЛЬЗЯ, т.к. произойдет
ошибка времени выполнения
"чтение за концом файла"}
write(f, 777); //можно
Close(f);
end.
<xh4>2 способа открытия файла</xh4>
- Reset(f) — открытие текстового файла на чтение, а двоичного — на чтение и запись;
файл должен существовать;
файловый указатель — на начало файла; - Rewrite(f) — создание нового файла (если такого файла не существовало) или обнуление существующего;
файловый указатель — в начало;
текстовые файлы при этом открываются только на запись, а двоичные — на чтение и запись;
Функция Eof(f) [расшифровывается как End Of File] возвращает true, если файловый указатель находился за концом файла.
После работы с данными в файле его необходимо закрыть с помощью Close(f).
Если, не закрывая, выполнить Reset(f), то файловый указатель просто перейдет к началу.
Буферизация в файлах
С каждым файлом связан некий буфер памяти, в который информация из файла частично считывается, и, из которого записывается в нужную часть файла.
Наличие буфера ускоряет операции чтения и записи, поскольку они выполняются преимущественно не с внешним устройством (файлом), а с участком оперативной памяти.
Если забыть закрыть файл, открытый на запись, то можно потерять лишь данные, сохраненные в буфере.
Подпрограммы для работы с закрытыми файлами
procedure Rename(f, name); //переименовывает файл, связанyый с файловой переменной f, давая ему имя name procedure Erase(f); //удаляет файл, связанный с файловой переменной f
function FileExists(name): boolean; //возвращает True, если файл с именем name существует function DeleteFile(name): boolean; //удаляет файл. Если файл не может быть удален, то возвращает False function RemoveDir(name): boolean; //удаляет каталог. Возвращает True, если каталог успешно удален function GetCurrentDir: string; //возвращает текущий каталог function SetCurrentDir(name): boolean; //устанавивает текущий каталог. Возвращает True, если каталог успешно установлен function CreateDir(name): boolean; //создает каталог. Возвращает True, если каталог успешно создан function ExtractFileName(name): string; //выделяет имя файла из полного имени файла name function ExtractFileExt(name): string; //выделяет расширение из полного имени файла name function ExtractFilePath(name): string; //выделяет путь из полного имени файла name
Типичные ошибки ввода-вывода при работе с файлами
- Файл открыли, но забыли выполнить Assign.
- Открыли, но файла нет на диске (или нет прав доступа на чтение).
- Попытка считывания за концом файла.
Все эти ошибки нужно обрабатывать с помощью исключений.
Пример 1. Файл не существует.
Assign(f, 'a.dat');
try
Reset(f);
read(f, x);
Close(f);
except
writeln('Файл не существует');
end;
<xh4>Оператор try..finally</xh4>
try <действия, которые могут вызвать исключение> finally <действия, которые надо выполнить независимо от того, произошло исключение, или нет> end;
Этот оператор отличается тем, что не обрабатывает исключение, а лишь выполняет некоторое завершающее действие, которое должно быть совершено в любом случае. Для обработки нужен внешний блок try..except.
Пример 2. Попытка считывания за концом файла.
Assign(f, 'a.dat');
try
Reset(f);
try
read(f, x);
finally
Close(f);
end;
except
writeln('Произошла ошибка ввода-вывода');
end;
Подпрограммы для работы с типизированными файлами
procedure Truncate(f) //Усекает типизированный файл f, отбрасывая все элементы с позиции файлового указателя function FileSize(f) //Возвращает количество элементов в типизированном файле f function FilePos(f) //Возвращает текущую позицию файлового указателя в типизированном файле f procedure Seek(f, i); //Устанавливает текущую позицию файлового указателя в типизированном файле f на элемент с номером i
<xh4>Варианты использования</xh4>
- Перейти на конец файла для добавления элементов:
Seek(f, FileSize(f));
- Перейти на предыдущую позицию:
Seek(f, FilePos(f) - 1);
Пример 1. Добавить в конец файла 'a.dat' элемент 0 (при необходимости создать файл).
const
fileName = 'a.dat';
var
f: file of integer;
begin
Assign(f, fileName);
if FileExists(fileName) then
begin
Reset(f);
Seek(f, FileSize(f));
end
else
Rewrite(f);
write(f, 0);
Close(f);
end.
Пример 2. Возведение всех элементов файла в квадрат.
const
fileName = 'a.dat';
var
f: file of real;
begin
Assign(f, fileName);
Reset(f);
for var i:=0 to FileSize(f)-1 do
begin
var x: real;
read(f, x);
Seek(f, i);
write(f, x * x);
end;
Close(f);
end.
Пример 3. Использование типизированных файлов для работы с простейшими БД.
БД студентов 1.11
Опишем запись для одного студента:
type
Student = record
name: string[50];
course, group: integer;
end;
Замечание. В связи с тем, что типизированные файлы хранят данные фиксированного размера, а string — переменной длины, использовать его в типизированных файлах мы не можем. Для этого будем использовать строки фиксированной длины — string[n] (строка длины n).
Пусть уже создан файл 'Group1course.dat'.
Задача. Найти Иванова и перевести его в 10 группу.
type
Student = record
name: string[50];
course, group: integer;
end;
const
fileName = 'a.dat';
var
f: file of Student;
begin
Assign(f, fileName);
Reset(f);
while not Eof(f) do
begin
var x: Student;
read(f, x);
if (x.name = 'Иванов') and (x.group = 11) then
begin
x.group := 10;
Seek(f, FilePos(f) - 1);
write(f, x);
break;
end;
end;
Close(f);
end.
Пример 4. Сортировка файла по возрастанию.
for var i:=FileSize(f)-2 downto 0 do
for var j:=0 to i do
begin
Seek(f,j);
read(f,x,y);
if x>y then
begin
Seek(f,j);
write(f,y,x);
end;
end;
Подпрограммы для работы с текстовыми файлами
procedure Reset(f) //Открывает текстовый файл f ТОЛЬКО на чтение. procedure Rewrite(f) //Открывает текстовый файл f ТОЛЬКО на запись, обнуляя его содержимое procedure Append(f) //Открывает текстовый файл f на дополнение //Файловый указатель устанавливается за концом файла function Eoln(f) //Возвращает True, если файловый указатель находится на символе конца строки в текстовом файле f function SeekEof(f) //Пропускает пробельные символы, после чего возвращает True, если достигнут конец текстового файла f function SeekEoln(f) //Пропускает пробельные символы, после чего возвращает True, если достигнут конец строки в текстовом файле f procedure read(f, a, b, c) //Считывает значения в переменные a, b, c; //Переменные могут быть числовых типов, символьного, строкового procedure write(f, a, b, c) //Записывает значения переменных a, b, c в текстовый файл f; //Переменные могут быть числовых типов, символьного, строкового procedure readln(f, a, b, c); procedure writeln(f, a, b, c); procedure readln(f); procedure writeln(f);
<xh4>Примеры использования</xh4>
Пример 1. Обработка строк в текстовых файлах.
Пусть имеется функция, которая трансформирует строку и возвращает string:
function Transform(var s: string): string;
Применить указанную трансформацию ко всем строкам файла.
var
f, f1: text;
begin
Assign(f, 'a.txt');
Assign(f1, 'b$.txt');
Reset(f);
Rewrite(f1);
while not Eof(f) do
begin
var s: string;
readln(f, s); //Важно использовать readLN, т.к. она пропускает символы перехода
//на новую строку (если использолвать read, произойдет зацикливание)
s := Transform(s);
writeln(f1, s);
end;
Close(f);
Close(f1);
Erase(f);
Rename(f1, 'a.txt');
end.