Способы обработки файлов последовательного и прямого доступа
Смысл последовательного доступазаключается в том, что в каждый момент времени доступна лишь одна компонента из всей последовательности. Для того, чтобы обратиться (получить доступ) к компоненте с номером К, необходимо просмотреть от начала файла К-1 предшествующую компоненту. После обращения к компоненте с номером К можно обращаться к компоненте с номером К+1. Отсюда следует, что процессы формирования (записи) компонент файла и просмотра (чтения) не могут произвольно чередоваться. Таким образом, файл вначале строится при помощи последовательного добавления компонент в конец, а затем может последовательно просматриваться от начала до конца.
Прямой доступ означает возможность заранее определить в файле блок, к которому будет применена операция ввода-вывода. В случае бестиповых файлов блок равен размеру буфера, для компонентных файлов блок – это одна компонента файла.
Прямой доступпредполагает, что файл представляет собой линейную последовательность блоков. Если файл содержит n блоков, то они нумеруются от 1 через 1 до n. Кроме того, вводится понятие условной границы между блоками, при этом условная граница с номером 0 расположена перед блоком с номером 1, граница с номером 1 расположена перед блоком с номером 2 и, наконец, условная граница с номером n находится после блока с номером n.
Реализация прямого доступа осуществляется с помощью функций и процедур FileSize, FilePos, Seek и Truncate.
------------------------------------------------------------------------------
Функция FileSize (var f): Longintвозвращает количество блоков в открытом файле f.
Функция FilePos (var f): Longintвозвращает текущую позицию в файле f. Позиция в файле – это номер условной границы. Для только что открытого файла текущей позицией будет граница с номером 0. Это значит, что можно записать или прочесть блок с номером 1. После чтения или записи первого блока текущая позиция переместится на границу с номером 1, и можно будет обращаться к блоку с номером 2. После прочтения последней записи значение FilePos равно значению FileSize.
Процедура Seek (var f; N: Longint)обеспечивает назначение текущей позиции в файле (позиционирование). В параметре N должен быть задан номер условной границы, предшествующей блоку, к которому будет производиться последующее обращение. Например, чтобы работать с блоком 4, необходимо задать значение N, равное 3. Процедура Seek работает с открытыми файлами.
Процедура Truncate (var f)устанавливает в текущей позиции признак конца файла и удаляет (стирает) все последующие блоки.
В тех случаях, когда программа обрабатывает достаточно большой объем данных, последние обычно организуются и хранятся вне оперативной памяти ЭВМ. Наиболее эффективным устройством для организации внешнего хранения данных являются диски. Прежде чем читать или записывать информацию в файл, надо открыть его с помощью стандартной библиотечной функции fopen.Программа, использующая эту функцию, должна включать во время компиляции системный файл stdio.h,в котором определен новый тип данных - FILE.
В программе нужно описывать ссылки на файлы и выглядит это, например, так: FILE *fu;
Здесь fuозначает указатель на FILE, а fopenвыдает ссылку на этот файл. Функция fopenимеет следующий заголовок:
FILE *fopen(char *fname, char type);
Обращение к fopenв программе делается так: fu=fopen(fname, type);
Строка символов fnameсодержит имя файла, который надо открыть;
type- тоже строка символов, заключенная в кавычки и указывающая, как будет использоваться файл: "r"-чтение, "w" - запись, "r+" - чтение с дозаписью, "a" -дозапись. Функция fopenвозвращает указатель, с помощью которого мы в дальнейшем будем обращаться к этому файлу.
Примеры:
FILE *uin, *uout;
uin=fopen("MAK1","r");
uout=fopen("MAK2","w");
Файл с именем MAK1открывается для чтения и далее идентифицируется как uin;
файл MAK2открывается для записи и связывается с идентификатором uout.
------------------------------------------------------------------------------
Язык (Турбо) СИ не содержит средств поддержки ввода/вывода. Каждая реализация СИ должна со-
провождаться библиотечными и макро, обслуживающими ввод/вывод. По мере развития СИ функции
ввода/вывода становились стандартизированными. Такая стандартизация обеспечила высокий уровень
мобильности программы на СИ.
Термин поток происходит из представления о последовательной структуре информационных запи-
сей [3]. Состав потока задается структурой FILE, описание которой задается в файле stdio.h.
Символ EOF определяется следующим образом:
#define EOF(-1)
Этот символ в операциях ввода/вывода служит для обозначения и проверки конца файла.
Функция fopen используется для открытия потока (файла). Интерфейс с функцией fopen описывает-
ся следующим образом:
FILE fopen(char filename, char type);
В качестве первого параметра функции должно передаваться правильное имя файла.
Второй параметр определяет тип открываемого файла.
Допустимы следующие типы файлов:
"r" Открыть уже существующий файл на ввод
"w" Создать новый файл или очистить уже существующий файл и
открыть его на вывод.
"a" Создать новый файл для вывода или осуществить вывод в конец уже существующего файла.
"r+" Открыть существующий файл для обновления, которое будет проводиться с начала файла.
"w+" Создать новый или открыть существующий файл для обновления его содержимого.
"a+" Создать новый файл или подстроиться в конец существующего файла для обновления его содер-
жимого.
Функция flclose выглядит следующим образом:
int fclose (FILE *stream);
С помощью этой функции файл закрывается.
Функция fseek описывается следующим образом:
int fseek (FILE *stream, long offset, int wherefrom);
Эта функция служит для произвольного доступа к байтам, обычно внутри двоичных потоков.
Первый аргумент задает поток, к которому должен осуществляться прямой доступ.
Второй аргумент указывает число байт смещения от точки, определяемой третьим параметром
функции.
Третий параметр указывает точку, от которой следует начинать отсчет смещения, заданного вто-
рым аргументом.
Значение 0 – смещение от начала файла.
Значение 1 – смещение от текущей позиции файла.
Значение 2 – смещение от конца файла.
5. ДИНАМИЧЕСКИЕ СТРУКТУРЫ
К динамическим структурам относят структуры, которые могут изменять свой размер.
Для организации таких структур используются динамические переменные, которые создаются и уничтожаются в процессе выполнения программы.
Характеризуются:
1. Эти переменные явным образом не описываются, к ним невозможно обратиться с помощью идентификатора.
2. Память для этих переменных не выделяется во время формирования кода программы. Она выделяется в специальной области оперативной памяти - heap-области - только во время выполнения программы.
3. Доступ к таким переменным выполняется с помощью указателей, которые становятся активными после определения динамического объекта и содержат адрес в виде <сегмент>:<смещение>
Структуры:
1. Массивы указателей
2. Линейные и циклические односвязанные списки, стек, очередь
3. Линейные двухсвязные списки
4. Деревья
Массив указателейна данные одного типа. Элементами такого массива есть указатели на базовую структуру: строка, запись, и т.п.. Хотя сам массив имеет фиксированный размер и занимает постоянное место в оперативной памяти, динамические элементы базового типа будут образовываться и размещаться в динамической памяти во время выполнения программы.
Линейный и циклический односвязанный список. Каждый отдельный элемент такой структуры содержит кроме одного или нескольких информационных полей поле, в котором сохраняется адрес следующего элемента. Последний элемент линейного списка содержит пустую ссылку (nil), тогда как последний элемент циклического списка содержит ссылку на первый элемент. Такие структуры образовываются и изменяются только во время работы программы.
Стек. С помощью линейного односвязного списка может быть построенный следующим образом: список будет возрастать из конца, от элемента с пустой ссылкой на следующий. Каждый очередной элемент будет прибавляться перед ним и становиться текущим (доступным для обработки - чтения). При чтении последнего элемента он уничтожается и указатель текущего элемента устанавливается на предыдущий.
Очередь. Также может быть построена с помощью линейного односвязного списка. Добавление элемента к очереди будет выполняться в конец списка (после последнего элемента), а считывание - из первого элемента со следующим его уничтожением. Таким образом надо будет сохранить два указатели - ссылка на первый и последний элементы очереди.
Двухсвязный список- такой, каждый элемент которого содержит две ссылки - на предыдущий и на следующий элементы. Первый элемент содержит пустую ссылку на предыдущий элемент, а последний - пустая ссылка на следующий элемент. Такой список также можно сделать циклическим.
Двоичные деревья могут также быть построены на базе элементов с двумя адресными полями. Одно из них содержит ссылку на левую, а второе - на правую ветвь поддерева, которое начинается с данного узла. Если одна из ветвей отсутствующая, в адресном поле, предназначенном для нее, содержится nil.