Работа с двоичными файлами. Библиотечные функции для работы с файлами. Ввод/вывод нижнего уровня
Выбери формат для чтения
Загружаем конспект в формате rtf
Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
Раздел 6. Файлы
Работа с двоичными файлами. Библиотечные функции для работы с файлами.
Ввод/вывод нижнего уровня
Чтение из двоичного файла и запись в него
Кроме текстовых файлов существует еще одна общая форма представления данных в файлах, на самом деле более многообразная – двоичный файл. Сюда относятся не только файлы с «мультимедийным» содержанием: документы, изображение, звук. Форматы двоичных файлов используются в базах данных и в самой файловой системе. Ведь файловая система – это не что иное, как большой двоичный файл, в котором построена сложная многоуровневая динамическая структура данных, включающая в себя все файлы каталоги.
Двоичный файл отличается от текстового тем, что данные в нем представлены во внутренней форме.
А поскольку при внутреннем представлении используется двоичная система счисления, то «в честь ее» файлы и называются двоичными. Но двоичная система интересует нас не сама по себе, а как основа внутреннего представления данных в компьютере.
Общеизвестно, что компьютеры используют двоичную систему. А что это значит, и почему именно ее? Во-первых, она самая технологичная, поскольку элементы с двумя устойчивыми состояниями (да-нет, включено-выключено) самые простые и самые надежные. Во-вторых, алгоритмы выполнения операций в этой системе тоже самые простые. Например, таблица умножения в десятичной системе имеет размерность 10х10, т.е. содержит 100 произведений всех пар цифр, а в двоичной системе всего 4.
По существу, двоичный файл является аналогом внутренней (оперативной, физической) памяти – неограниченным массивом байтов с возможностью непосредственного обращения (произвольного доступа) к любой его части.
Такая модель файла полностью совпадает с системой представлений, принятой в Си для работы с памятью на низком (физическом уровне).
· физическая память имеет байтную структуру – единицей адресации является байт;
· любая переменная занимает фиксированное количество байтов, определяемое ее типом. Операция sizeof возвращает эту размерность;
· указатель на переменную интерпретируется как ее адрес в памяти. Преобразование типа указателя к void* позволяет интерпретировать его как «чистый» адрес, а преобразование к char* - как указатель на массив байтов (физическое представление памяти).
Функции двоичного ввода-вывода fread и fwrite переносят содержимое памяти в двоичный файл «прозрачно», т.е. байт в байт без каких-либо преобразований.
При использовании исключительно функций fread/fwrite данные, записанные в определенной последовательности в файл, хранятся в нем и читаются в том же самом порядке. Этот неизменный порядок извлечения данных называется последовательным доступом, а файл - последовательным двоичным файлом. Естественно, что нас при этом не интересуют адреса размещения данных в файле. Однако существует и другой способ, позволяющий извлекать данные в любом произвольном порядке – прямой (или произвольный) доступ.
Произвольный доступ базируется на понятии адреса в двоичном файле. Поскольку на физическом уровне двоичный файл представляется как «неограниченно растущий» массив байтов, то под адресом понимается порядковый номер байта, начиная с 0.
В Си для представления адресов используются переменные типа long, на которые можно распространить известное понятие указатель - указатель в файле. Такая образная аналогия вполне уместна и позволяет с общих позиций рассматривать структуры данных, размещенные в файлах. Указатель в файле не является типизированным, его тип никак не связан с типом адресуемых данных, и он рассматривается как «чистый» физический адрес в файле.
Но для начала обсудим, как произвольный доступ и система адресации поддерживается библиотекой ввода-вывода. С каждым открытым файлом связывается такой параметр как текущая позиция (текущий адрес) - номер байта, начиная с которого будет выполняться очередная операция чтения-записи. При открытии файла текущая позиция устанавливается на начало файла, после чтения-записи порции данных перемещается вперед на размерность этих данных. Для дополнения файла новыми данными необходимо установить текущую позицию на конец файла и выполнить операцию записи.
Замечание: текущая позиция в файле является адресом размещения переменной в нем, но получить этот адрес можно перед, и не после ее чтения оттуда.
Бинарный (двоичный) файл отличается от текстового тем, что не обязательно состоит из печатаемых символов со стандартными разделителями между ними.
Следовательно, для него не имеет смысла понятие "строки данных", а основной способ работы с ним – чтение и запись наборов байтов указанного размера.
С файлом можно работать не как с последовательностью символов, а как с последовательностью байтов. В принципе, с нетекстовыми файлами работать по-другому невозможно. Однако так можно читать и писать и в текстовые файлы. Преимущество такого способа доступа к файлу заключается в скорости чтения-записи: за одно обращение можно считать/записать существенный блок информации.
При открытии файла для двоичного доступа, вторым параметром функции fopen() является строка "rb" или "wb".
Работа с двоичными файлами достаточно сложная. Отметим только особенности функций чтения-записи в файл, который рассматривается как поток байтов.
Основные функции для чтения и записи бинарных данных – fread и fwrite соответственно.
В базовой реализации fread и fwrite они имеют по четыре параметра:
1. void *buffer – не типизированный указатель на место хранения данных;
2. size_t size – размер элемента данных в байтах, тип данных size_t обычно определён как unsigned;
3. size_t count – максимальное количество элементов, которое требуется прочитать или записать;
4. FILE *stream – указатель на структуру FILE.
Функция fread( ) предназначена для чтения блоков данных из потока (файла). Имеет прототип:
unsigned fread (void *ptr, unsigned size, unsigned n, FILE *fp);
Она читает n элементов данных, длиной size байт каждый, из заданного входного потока fp в блок, на который указывает указатель ptr. Общее число прочитанных байтов равно произведению n*size. При успешном завершении функция fread( ) возвращает число прочитанных элементов данных, при ошибке - 0.
Функция fwrite( ) предназначена для записи в файл блоков данных. Имеет прототип:
unsigned fwrite (void *ptr, unsigned size, unsigned n, FILE *fp);
Она добавляет n элементов данных, длиной size байт каждый, в заданный выходной файл fp. Данные записываются с позиции, на которую указывает указатель ptr. При успешном завершении операции функция fwrite( ) возвращает число записанных элементов данных, при ошибке - неверное число элементов данных.
Итак, функции fread( и fwrite() принимают в качестве параметров:
1. адрес области памяти, куда данные записываются или откуда считываются,
2. размер одного данного какого-либо типа,
3. количество считываемых данных указанного размера,
4. файловый указатель.
Эти функции возвращают количество успешно прочитанных или записанных данных. Т.е. можно "заказать" считывание 50 элементов данных, а получить только 10. Ошибки при этом не возникнет.
Пример 1. Целочисленный массив a запишем в двоичный файл:
FILE *fp=fopen ("data.dat", "wb");
if (fp==NULL)
{
puts ("Не удалось открыть файл");
getchar ();
exit (1);
}
const int n=10;
int a[n];
for (int i=0; i
#include
int main ()
{
FILE *file;
char shelf1[50], shelf2[100];
int n, m;// кол-во реально считанных символов
file = fopen ("shelf1.txt", "rb");
n=fread (shelf1, sizeof(char), 50, file); // считать из 1-го файла
fclose(file);
file = fopen ("shelf2.txt", "rb");
m=fread (shelf2, sizeof(char), 50, file); // считать из 2-го файла
fclose(file);
shelf1[n] = '\0';
shelf2[m] = '\n';
shelf2[m+1] = '\0';
file = fopen ("shop.txt", "wb");
fwrite (strcat (shelf2, shelf1), sizeof(char), n+m, file); // записать в 3-й файл
fclose(file);
}
Здесь осуществляется попытка чтения из первого файла 50-ти символов. В n сохраняется количество реально считанных символов. Значение n может быть равно 50 или меньше. Данные помещаются в строку. То же самое происходит со вторым файлом. Далее первая строка присоединяется ко второй, и данные сбрасываются в третий файл.
Для файлов, открытых в режиме "r+b", разрешены и чтение, и запись (прямой (или произвольный) доступ). Поэтому при работе с такими файлами нужны функции позиционирования файлового указателя. Текущую позицию можно читать и устанавливать с помощью функций позиционирования, которые превращают последовательный файл в файл произвольного доступа.
Функция long ftell(FILE *fp) возвращает текущую позицию в файле. Если по каким-то причинам текущая позиция не определена, функция возвращает -1. Это же самое значение будем использовать в дальнейшем для представления недействительного значения файлового указателя (файловый NULL), самостоятельно определив его
#define FNULL -1L
Функция int fseek(FILE *fp, long pos, int mode) устанавливает текущую позицию в файле на байт с номером pos. Параметр mode определяет, относительно чего отсчитывается текущая позиция в файле, и имеет символические и числовые значения (установленные в stdio.h):
#define SEEK_SET 0 // Относительно начала файла, начало файла - позиция 0
#define SEEK_CUR 1// Относительно текущей позиции, >0 - вперед, <0 - назад
#define SEEK_END 2 // Относительно конца файла (значение pos - отрицательное)
Функция fseek возвращает значение 0 при успешном позиционировании и -1 (EOF) - при ошибке. Различные значения параметра mode определяют различные способы адресации данных в файле:
· значение SEEK_SET определяет абсолютную адресацию данных в файле от его начала. Заметим, что функция ftell возвращает текущую позицию в абсолютном значении;
· значение SEEK_END за начало координат берет конец файла (EOF). Адреса уже записанных данных имеют отрицательное значение. Например, если в конце файла находится целая переменная, то ее позиция при адресации от конца файла будет иметь значение 0–sizeof(int). В этом же режиме можно определить текущую длину файла можно простым позиционированием:
long fsize;
fseek(fl,0L,SEEK_END); // Установить позицию на конец файла
fsize = ftell(fd); // Прочитать значение текущей позиции
· значение SEEK_CUR дает способ относительной адресации от текущего положения указателя в файле. Таким образом, задается расстояние в байтах от текущей переменной до адресуемой. Если это расстояние само находится в файле, то оно обычно носит название смещения.
Чтение текущей позиции указателя в файле позволяет выполнить и функция fgetpos;
Переход к нужной позиции в файле позволяют осуществить и функция fsetpos.
Пример 2. Определить размер файла в байтах. Предположим, что файл уже открыт в режиме чтения или произвольного доступа.
fseek (fp, 0, SEEK_END);
//0 байт от конца файла
long int pos;
pos = ftell (fp);
//Получили текущую позицию
if (pos < 0)
puts ("\n Ошибка");
else if (!pos)
puts ("\nФайл пуст");
else
printf ("\nВ файле %ld байт", pos);
В двоичном файле возможность неограниченного расширения файла путем записи данных в его конец дает нам самый простой способ распределения памяти: для размещения переменной в файле достаточно дописать ее в конец файла, запомнив ее новый адрес.
Пример 3. Добавить в файл вещественную переменную
double b=5.6;
fseek (fd,0L, SEEK_END); // Позиционироваться на конец файла
long pp=ftell(fd); // Адрес переменной в файле
fwrite (&b, sizeof(double), 1, fd); // Записать b как массив байтов
Изменение данных в файле не может быть выполнено непосредственно. Необходимо создать в памяти переменную, прочитать туда значение из файла, а после изменения записать обратно (обновить).
// Обновить счетчик в двоичном файле
int a; long pos;
fseek (fd, pos, SEEK_SET);
fwrite((void*) &a, sizeof(int), 1, fd); // Читать счетчик
a++; // Увеличить в памяти
fseek (fd, pos, SEEK_SET);
fwrite((void*) &a, sizeof(int), 1, fd); // Записать обратно по тому же адресу
Рассмотрим другие библиотечные функции, используемые для работы с файлами (все они описаны в файле stdio.h):
Функция feof( ) определяет конец файла при чтении двоичных данных и имеет следующий прототип:
int feof(FILE *fp);
Здесь fp - указатель на файл, возвращенный функцией fopen( ). При достижении конца файла возвращается ненулевое значение, в противном случае возвращается 0.
Функция ferror( ) позволяет проверить правильность выполнения последней операции при работе с файлами. Имеет следующий прототип:
int ferror(FILE *fp);
В случае ошибки возвращается ненулевое значение, в противном случае возвращается нуль.
Функция remove( ) удаляет файл и имеет следующий прототип:
int remove (char *file_name);
Здесь file_name - указатель на строку со спецификацией файла. При успешном завершении возвращается нуль, в противном случае возвращается ненулевое значение.
Функция rewind( ) устанавливает указатель текущей позиции в начало файла и имеет следующий прототип:
void rewind(FILE *fp);
Следующая группа программ демонстрирует работу с файлами. Она позволяет организовать в файле на диске телефонный справочник и выполняет следующие функции:
занесение фамилии абонента и номера телефона в справочник;
поиск в справочнике номера телефона по фамилии абонента;
удаление из справочника фамилии абонента и номера его телефона.
Ниже приведен текст головной программы main.c:
// Пример
//---------------------------------------------------------
// Головная программа для работы с телефонным справочником
//---------------------------------------------------------
#include "my.h" //Заголовочный файл с глобальными
//переменными и константами
#include "findt.c" //Поиск строки str в файле
#include "choicet.c" //Проверка наличия строки в файле
#include "addt.c" //Добавление строки в файл
#include "subt.c" //Удаление строки из файла
void main (int argc, char *argv[ ])
{
if (argc == 3)
if (*argv[1] == '+') //Добавить запись
{
if (Choice(argv[2]) == 0) //Нет ли такой
//записи в файле?
{
puts("Эта фамилия есть в справочнике");
exit(1);
}
Add(argv[2]); //Добавление записи
}
else if (*argv[1] == '-')
Sub(argv[2]); //Удалить запись
else puts("Ошибочное значение аргумента");
else if (argc == 2)
Find (argv [1]); //Поиск записи
else puts("Ошибочное число аргументов");
}
С помощью директив #include в головную программу включаются файлы: my.h, findt.c, choicet.c, addt.c и subt.c. Считается, что все они находятся в корневом каталоге диска b: . Если это не так, то необходимо изменить соответствующие директивы #include. В файле my.h определены глобальные переменные и некоторые символьные значения.
//Файл заголовков my.h
//--------------------------------------------------------
//Определения глобальных переменных и символьных значений
//--------------------------------------------------------
#include
#include
#include
#define MAX_NAME 20 //Максимальное число символов в фамилии
#define MAX_NUMBER 10 //Максимальное число цифр в телеф. номере
char Name[MAX_NAME]; //Строка для фамилии
char Number[MAX_NUMBER]; //Строка для телефонного номера
char File[ ] = "b:\\tel\\tel_num.txt"; //Имя файла справочника
int Count; //Число фамилий в справочнике
FILE *F_tel; //Логическое имя файла справочника
Файл my.h, в частности, определяет, что телефонный справочник будет организован в каталоге tel диска b: . Поэтому необходимо перед запуском программы main.c создать этот подкаталог либо использовать другой подкаталог. В последнем случае необходимо изменить строку:
char File[ ] = "b:\\tel\\tel_num.txt";
эта строка также задает имя файла с телефонным справочником (tel_num.txt).
Модуль findt.c, текст которого приведен ниже, содержит функцию Find( ) для поиска строки str в файле tel_num.txt.
//Модуль findt.c
//----------------------------------------------------------
//Функция Find( ) для поиска строки str в файле tel_num.txt
//----------------------------------------------------------
void Find (char *str)
{
int i;
//Если файл невозможно открыть для чтения, то программа
//завершает работу
if ((F_tel = fopen (File, "r")) == NULL)
{
fprintf (stderr, "\"%s\»: невозможно открыть\n", File);
exit(1);
}
//Чтение числа записей (Count) в файле
if (fread (&Count, sizeof(int), 1, F_tel) != 1)
{
fprintf (stderr, "\"%s\»: ошибка чтения\n", File);
exit(1);
}
//В цикле for осуществляется поиск нужной записи
for (i = 1; i < Count; i++)
{
fread (Name, 1, MAX_NAME, F_tel); //Чтение имени
fread (Number, 1, MAX_NUMBER, F_tel); //Чтение номера
if (ferror(F_tel)) //Проверка отсутствия ошибки
{
fprintf(stderr, "\"%s\" : ошибка чтения\n'', File);
exit(1);
}
if (strcmp(str, Name) == 0) //Если имя совпадает
//с введенным, то фамилия
//и найденный номер
//выводятся на экран
{
printf("Фамилия : %s\n", Name);
printf ("Номер телефона: %s\n", Number);
fclose(F_tel);
return;
}
}
//Если результат поиска отрицательный, то выводится
//следующее сообщение
fprintf(stderr,"\"%s\" : запись в файле отсутствует\n", File);
fclose(F_tel);
return;
}
Модуль choicet.c содержит функцию Choice( ), позволяющую проверить есть ли заданная строка в файле tel_num.txt.
// Модуль choicet.c
//----------------------------------------------------------------------
//Функция Choice( ), проверяющая есть ли строка str в файле tel_num.txt
//----------------------------------------------------------------------
int Choice (char *str)
{
int i;
char temp [MAX_NAME + MAX_NUMBER]; // локальная строка для фамилии и номера
//Если файл невозможно открыть для чтения, то программа
//завершает работу
if ((F_tel = fopen (File, "r")) == NULL)
return 1; //Строки str нет в файле
//Чтение числа записей (Count) в файле
if (fread (&Count, sizeof(int), 1, F_tel) != 1)
{
fprintf (stderr, "\"%s\" : ошибка чтения\n", File);
exit (1);
}
for (i = 0; i < Count; i++)
{
fread (temp, 1, MAX_NAME + MAX_NUMBER, F_tel); // считать фамилию+номер
if (ferror(F_tel))
{
fprintf (stderr, "\"%s\" : ошибка чтения\n", File);
exit (1);
}
if (strcmp (str, temp) == 0)
{
fclose(F_tel);
return 0; //Строка str есть в файле
}
}
fclose(F_tel);
return 1; //Строки str нет в файле
}
Модуль addt.c содержит функцию Add( ), которая добавляет заданную строку в файл tel_num.txt.
//Модуль addt.c
//-------------------------------------------------------
//Функция Add( ) добавляет строку str в файл tel_num.txt
//-------------------------------------------------------
void Create(void) //Создает файл, если он не существует
{
if ((F_tel = fopen (File, "wb+")) == NULL)
{
fprintf (stderr, "\%s\": невозможно открыть\n", File);
exit (1);
}
Count = 0;
if (! fwrite (&Count, sizeof (Count), 1, F_tel))
{
fprintf (stderr, "\"%s\": ошибка записи\n", File);
exit(1);
}
}
void Add(char *s) //Добавляет запись в файл
{
char str [MAX_NAME], sn [MAX_NUMBER]; //Временные строки
int i;
for (i = 0; i < MAX_NAME; i++)
str[i] = ' '; //Пробелы в str
strcpy(str, s); //Копирование строки в str
if ((F_tel = fopen (File, "rb+")) = = NULL)
Create(); //Создаем файл, если он не
//существует
else if (fread (&Count, sizeof (Count), 1, F_tel) != 1) /*считаем количество записей*/
{
fprintf (stderr, "\"%s\": ошибка чтения\n", File);
exit(1);
}
printf("Номер телефона : "); //Запрашивается и вводится номер
if (gets (Number) == NULL || *Number == '\0')
{
fclose(F_tel);
return; //Возврат, если номер не введен
}
//Установка указателя в файле на первую свободную запись
if (fseek (F_tel, (long)((MAX_NAME+MAX_NUMBER) *Count), SEEK_CUR)!=0)
{
fprintf (stderr, "\"%s\": ошибка поиска\n", File);
exit (1);
}
fwrite (str, 1, MAX_NAME, F_tel); //Запись в файл фамилии
for (i = 0; i < MAX_NUMBER; i++)
sn[i] = ' '; //Пробелы в строку sn
strcpy(sn, Number); //Копирование сроки Number в строку sn
fwrite(sn, 1, MAX_NUMBER, F_tel); //Запись в файл номера
if (ferror(F_tel)) //Проверка наличия ошибки
{
fprintf (stderr, "\"%s\": ошибка записи\n", File);
exit(1);
}
//Установка указателя в файле на первый байт
if (fseek (F_tel, 0L, SEEK_SET) != 0)/*0L – нуль длинное целое, Для хранения требуется 4 байта.*/
{
fprintf (stderr, "\"%s\": ошибка позиционирования\n", File);
exit(1);
}
++Count; //Увеличение числа записей на единицу
//Запись Count в файл
if (fwrite (&Count, sizeof(int), 1, F_tel) != 1)
{
fprintf (stderr, "\"%s\": ошибка записи\n", File);
exit (1);
}
fclose(F_tel);
return;
}
Модуль subt.c содержит функцию Sub( ), которая удаляет заданную строку из файла tel_num.txt.
//Модуль subt.c
//------------------------------------------------------------
//Функция Sub( ) удаляет заданную строку из файла tel_num.txt
//------------------------------------------------------------
void Sub (char *str)
{
int i, j;
char temp [MAX_NAME + MAX_NUMBER]; //Временная строка
if ((F_tel = fopen (File, "r+")) == NULL)
{
fprintf (stderr, "\"%s\": невозможно открыть\n", File);
exit (1);
}
if (fread (&Count, sizeof(int), 1, F_tel) != 1/*считаем количество записей*/
{
fprintf (stderr, "\"%s\": ошибка чтения\n", File);
exit(1);
}
//В цикле осуществляется поиск удаляемой строки в файле
for (i = 0; i < Count; i++)
{
fread (temp, 1, MAX_NAME + MAX_NUMBER, F_tel); /*считаем фамилию+телефон*/
if (ferror(F_tel))
{
fprintf (stderr, "\"%s\": ошибка чтения\n", File);
exit(1);
}
if (strcmp (str, temp) == 0) //Если строка найдена
{
for (j = i; j < Count; j++) //она удаляется
{
fread (temp, 1, MAX_NAME + MAX_NUMBER, F_tel);
fseek (F_tel, (long)(j*(MAX_NAME+MAX_NUMBER) +2L), SEEK_SET);
fwrite (temp, 1, MAX_NAME + MAX_NUMBER, F_tel); /*перезапись следующей фамилии и телефон в файле*/
fseek (F_tel, (long)((j+2) *(MAX_NAME+MAX_NUMBER) +2L), SEEK_SET);
if (ferror(F_tel))
{
fprintf (stderr, "\"%s\» ошибка чтения\n", File);
exit(1);
}
}
--Count; //При удалении строки декремент Count
fseek(F_tel, 0L, SEEK_SET); //Установка указателя на начало
//Запись уменьшенного значения Count в файл
if (fwrite (&Count, sizeof (Count), 1, F_tel) != 1)
{
fprintf (stderr, "\"%s\" : ошибка записи\n", File);
exit(1);
}
fclose(F_tel);
puts("Запись удалена из файла");
return;
}
}
fprintf(stderr, "\"%s\" : отсутствует в базе данных\n", File);
fclose(F_tel);
}
Ниже приводится возможный сценарий работы с программой main.
main + Петров
Номер телефона: 77-17-89
main + Иванов
Номер телефона: 52-98-02
main Иванов
Фамилия: Иванов
Номер телефона: 52-98-02
main - Петров
Запись удалена из файла
main Петров
"tel_num.txt" : запись в файле отсутствует
Последняя программа showt.c позволяет вывести на экран содержимое телефонного справочника.
//Программа showt.c
//-------------------------------------------------
//Выводит на экран все записи из файла tel_num.txt
//-------------------------------------------------
#include "my.h"
void Show(void)
{
int i;
//Если файл невозможно открыть для чтения, то завершение работы программы
if ((F_tel = fopen (File, "r")) == NULL)
{
fprintf (stderr, "\"%s\": невозможно открыть\n", File);
exit(1);
}
//Чтение числа записей (Count) в файле
if (fread (&Count, sizeof(int), 1, F_tel) != 1)
{
fprintf (stderr, "\"%s\": ошибка чтения\n", File);
exit(1);
}
//В цикле осуществляется вывод всех записей
for (i=0; i < Count; i++)
{
fread (Name, 1, MAX_NAME, F_tel); //Читается имя
fread (Number, 1, MAX_NUMBER, F_tel); //Читается номер
if (ferror(F_tel)) //Проверяется отсутствие ошибки
{
fprintf (stderr, "\"%s\": ошибка чтения\n'', File);
exit (1);
}
printf ("Фамилия: %s; номер телефона: %s\n", Name, Number);
}
fclose(F_tel);
}
void main(void)
{
Show( );
}
Ввод/вывод нижнего уровня
Функции языка С позволяют осуществлять:
- ввод/вывод верхнего уровня (потоковый ввод-вывод)
- ввод/вывод нижнего уровня (с использованием понятия "дескриптор").
В языке Си имеется также система низкоуровневого ввода/вывода (без буферизации и форматирования данных), соответствующая стандарту системы UNIX.
Прототипы составляющих ее функций находятся в файле io.h.
К этим функциям относятся:
open( ) - открыть файл;
close( ) - закрыть файл;
read( ) - читать данные;
write( ) - записать данные;
lseek( ) - поиск определенного байта в файле;
unlink( ) - уничтожить файл.
Функции в/в низкого уровня не выполняют буферизацию и форматирование данных; они позволяют непосредственно пользоваться средствами ввода/вывода операционной системы. При низкоуровневом открытии файла (при помощи функции open) с ним связывается дескриптор (handle).
HANDLE - дескриптор, предназначенный для описания различных объектов. На самом деле этот тип представляет собой ни что иное, как указатель на void, т.е. как бы на любой тип, т.е. это число, которое представляет собой идентификатор какой-то структуры или объекта операционной системы. По сути, это -- адрес этой структуры в памяти, только память эта не обязательно доступна (и как правило недоступна) приложению, а доступна только компонентам операционной системы.
Дескриптор является целым значением, характеризующим размещение информации об открытом файле во внутренних таблицах системы. Дескриптор используется при последующих операциях с файлом.
Ввод-вывод нижнего уровня основан на системных вызовах read и write, к которым Си-программа обращается с помощью функций read и write.
ssize_t read (int fd, void * buf, size_t count) ;// читать
ssize_t write (int fd, const void * buf, size_t count) ;//записывать
Для обеих первым аргументом является дескриптор файла (дескрипторы 0, 1 и 2, которые называются соответственно стандартным вводом, стандартным выводом и стандартным файлом ошибок). Во втором аргументе указывается массив символов вашей программы, куда посылаются или откуда берутся данные. Третий аргумент — это количество пересылаемых байтов.
int n_read = read (int fd, char *buf, int n);
int n_written = write (int fd, char *buf, int n);
Функция read () пытается прочитать до подсчета байтов из файлового дескриптора f в буфер, начиная с buf и возвращает количество успешно переданных БАЙТОВ или -1 в случае ошибки
Пример:
double dat [100];
int fd = open ("inputfile.dat", O_RDWR) // O_RDWR -- флаг
if (read (fd, data, 100 * sizeof (double))! = 100 * sizeof (double))
{
fprintf (stderr, «Ошибка: не удалось прочитать! \ n»);
выход (-1);
}