- •Структуры и алгоритмы обработки данных Введение
- •1. Структуры данных
- •1.1 Уровни структур данных
- •1.2 Классификация структур данных
- •1.3. Информация и ее представление в памяти эвм
- •2. Простые структуры данных
- •2.1. Понятие о типах данных
- •2.2. Перечисляемый тип данных
- •2.3. Стандартные типы данных
- •2.3.1. Целочисленные типы
- •2.3.2. Вещественные числа
- •2.3.3. Представление и структуры хранения логической информации
- •2.4. Указатели
- •2.4.1. Назначение и смысл указателей
- •2.4.2 Операции с адресами
- •2.4.3 Указатели на указатели
- •2.5. Алгоритмы обработки простых структур данных
- •3. Линейные статические структуры данных
- •3.1 Массивы
- •3.2. Динамические массивы
- •3.3. Многомерные массивы
- •3.4. Связь массивов с указателями
- •3.5. Строки
- •3.6. Массивы указателей
- •3.7. Интерпретация составных описателей
- •3.8 Алгоритмы обработки статических линейных струткур
- •4. Ссылки
- •5. Интегральные типы данных (структуры, битовые поля, объединения)
- •5.1. Структуры
- •5.2. Битовые поля
- •5.3. Объединения
- •6. Файлы
6. Файлы
Файл представляет собой последовательность элементов необязательно одного типа, хранящихся на внешнем запоминающем устройстве, переменной длины, имеющую уникальное имя среди всех остальных файлов на этом же устройстве.
В разных языках программирования высокого уровня файлы могут разделяться по типам, как например, в Паскале, где могут быть файлы текстовые, типизированные или нетипизированные (см. рис. 1.3). В других языках, например, Си/Си++ нет явного деления файлов по типам. Один и тот же файл может быть открыт для записи или для считывания как двоичный или как текстовый, в зависимости от текущих требований программиста.
Существует несколько способов доступа к файлам в программах при использовании языка Си++. Один из них – использование указателя на тип FILE, который может считаться аналогом файловой переменной в Паскале, только такая «файловая переменная» никак не связана с типом файлов. Этот указатель требуется для большинства библиотечных функций работы с файлами, описанных в заголовочном файле stdio.h. Этот указатель, так же как и файловую переменную в языке Паскаль, можно представить как логическое имя файла, используемое библиотечными функциями.
Для доступа к элементам файла он должен быть открыт. Функция fopen приводит физическое имя файла в соответствии с логическим и открывает файл.
#include <stdio.h>
FILE *file;
void main()
{
//…
file = fopen(”имя_файла”,”w”);
//…
Файл может быть открыт для: записи – ”w”, чтения – ”r”, дополнения – ”a”. Если файл открывается для записи или дополнения, но ещё не существует, то он создаётся (если это можно сделать). Открытие существующего файла для записи приводит к уничтожению его имеющегося содержимого.
Примеры других режимов открытия файлов: ”r+” – открытие файла для добавления, ”r+t” – открытие текстового файла для добавления, ”wt” – открытие текстового файла для записи, ”rb” – открытие двоичного файла для чтения. Именно здесь и выбирается, как будет тркаторваться файл – как текстовый, или как двоичный.
После окончания работы с файлом он должен быть закрыт:
//…
fclose(file);
}
Другой способ доступа к файлам – использование в качестве «файловой переменной» целого числа (конкретно знакового длинного целого числа) – handle, handler. В этом случае используются библиотечные функции такого же характера, что и при использовании указателя на тип FILE, но немного отличающиеся по названию.
Ещё один способ – использование объектов из библиотеки классов потокового ввода-вывода, аналогичных объектам cin и cout, в частности, объектов классов ifstream и ofstream. В этом случае также используются соответсвующие библиотечные функции.
При создании программ для операционной системы Windows можно также применять функции доступа к файлам из библиотеки Windows API, а при использовании инструментальной системы Borland C++ Builder – функции записи и считывания в/из файл из состава классов этой системы.
Поскольку файл представляет собой последовательность элементов, с ним можно работать, как с линейной структурой данных, т.е. использовать последовательные алгоритмы. В то же время при помощи соответствующих библиотечных функций можно обращаться к произвольным элементам файла, аналогично возможности обращения к произвольным элементам массива.
Рассмотрим библиотечные функции работы с файлами, использующие указатель на тип FILE. Эти функции можно разделить на две группы: вспомогательные и записи/чтения.
Вспомогательные функции:
FILE* fopen(char* name, char* code); – открытие файла (рассмотрена выше)
int fclose(FILE* file); – закрытие файла
int access(char* name, int n); – проверка файла; режим проверки определяется аргументом n, n = 0 – проверка на существование, 1 – на выполняемость, 2 – на запись, 4 – на чтение, 6 – на запись и чтение, 7 – на запись, чтение и выполняемость и т.д. При успешном завершении функция возвращает 0.
int fileno(FILE* file); – возвращает целочисленный идентификатор (handler) файла. Эта функция обеспечивает связь этого идентификатора и указателя на тип FILE. Целочисленный идентификатор необходим для следующей функции.
long filelength(int handle); – возвращает длину файла в байтах. Тип long позволяет создавать файлы длиной не более 2 Гигабайт.
int fseek(FILE* file, long pos, int sign); – перемещение текущей позиции записи/считывания в файле в точку, указываемую аргументом pos, отсчёт выполняется от начала файла, если аргумент sign = 0, от конца файла при sign = 2, от текущей позиции при sign = 1.
long ftell(FILE* file); – возвращает текущую позицию в файле. Эта функция полезна для предыдущей.
int rewind(FILE* file); – перемещение текущей позиции в начало файла.
int rename(char* old_name, char* new_name); – переименование файла
int unlink(char* name); – самая опесная функция – удаление файла
Функции записи/считывания
int getc(FILE* file); – считывание символа (байта), несмотря на то, что возвращает значение типа int.
int getw(FILE* file); – считывание целого числа
int putc(int c, FILE* file); – запись символа
int fputs(const char* s, FILE* file); – запись строки
char* fgets(char* s, int n, FILE* file); – считывание строки длиной n–1 символ
int fread(void* block, size_t size, size_t items, FILE* file); – считывание из файла в блок памяти, адресуемый указателем block, данных в количесве items элементов, каждый элемент размером size байт. Указатель на тип void используется потому, что неизвестен заранее точный тип считываемых данных. size_t – один из переименованных целых типов (для 32-разрядных систем – часто беззнаковый целый), определён в заголовочном файле stddef.h. Аргументы size и items – взаимозаменяемые, например, можно прочитать 1 блок данных размером 1000 байт или 1000 блоков размером 1 байт.
size_t fwrite(const void* block, size_t size, size_t items, FILE* file); – запись блока в файл. Блок помечен как константный, чтотбы внутри функции его нельзя было модифицировать.
Кроме этих функций запись в текстовый файл может выполняться функцией fprintf(), а считывание – функцией fscanf(). Обе эти функции относятся к функциям с переменным числом аргументов, рассмотрение которых выходит за рамки настоящего курса.