При записи информации в двоичный файл символы и числа записываются в виде последовательности байт.
Для того чтобы записать данные в двоичный файл, необходимо:
- описать файловую переменную типа FAIL * с помощью оператора FILE *filename, здесь filename — имя переменной, где будет храниться указатель на файл.
- открыть файл с помощью функции fopen
- записать информацию в файл с помощью функции fwrite
- закрыть файл с помощью функции fclose
Для того чтобы считать данные из двоичного файла, необходимо:
- описать переменную типа FILE *
- открыть файл с помощью функции fopen
- считать необходимую информацию из файла с помощью функции fread, при этом следить за тем достигнут ли конец файла.
- закрыть файл с помощью функции fclose
Рассмотрим основные функции, необходимые для работы с двоичными файлами.
Для открытия файла предназначена функция fopen.
FILE *fopen(const *filename, const char *mode)
Здесь filename — строка, в которой хранится полное имя открываемого файла, mode — строка, определяющая режим работы с файлом; возможны следующие значения:
- «rb» — открываем двоичный файл в режиме чтения;
- «wb» — создаем двоичный файл для записи; если он существует, то его содержимое очищается;
- «ab» — создаем или открываем двоичный файл для дозаписи в конец файла;
- «rb+» — открываем существующий двоичный файл в режиме чтения и записи;
- «wb+» — открываем двоичный файл в режиме чтения и записи, существующий файл очищается;
- «ab+» — двоичный файл открывается или создается для исправления существующий информации и добавления новой в конец файла.
Функция возвращает в файловой переменной f значение NULL в случае неудачного открытия файла. После открытия файла доступен 0-й его байт, указатель файла равен 0, значение которого по мере чтения или записи смещается на считанное (записанное) количество байт. Текущие значение указателя файла — номер байта, начиная с которого будет происходить операция чтения или записи.
Для закрытия файла предназначена функция fclose:
int fclose(FILE *filename);
Она возвращает 0 при успешном закрытие файла и EOF в противном случае.
Функция remove предназначена для удаления файлов:
int remove(const char *filename);
Эта функция удаляет с диска файл с именем filenema. Удаляемый файл должен быть закрыт. Функция возвращает ненулевое значение, если файл не удалось удалить.
Для переименования файлов предназначена функция rename:
int rename(const char *oldfilename, const char *newfilename);
Первый параметр — старое имя файла, второй — новое. Возвращает 0 при удачном завершении программы.
Чтение из двоичного файла осуществляется с помощью функции fread:
fread(void *ptr, size, n, FILE *filename);
Функция fread считывает из файла filename в массив ptr n элементов размера size. Функция возвращает количество считанных элементов. После чтения из файла его указатель смещается на n*size байт.
Запись в двоичный файл осуществляется с помощью функции fwrite:
fwrite(const void *ptr, size, n, FILE *filename);
Функция fwrite записывает в файл filename из массива ptr n элементов размера size. Функция возвращает количество записанных элементов. После записи информации в файл указатель смещается на n*size байт.
Для контроля достижения конца файла есть функция feof:
int feof(FILE *filename);
Она возвращает ненулевое значение если достигнут конец файла.
Для более точного усвоения материала предлагаю рассмотреть пару стандартных задач.
Задача 1
Создать двоичный файл D:\\game\\noobs.dat и записать в него целое число n и n вещественных чисел.
Решение:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#include «stdafx.h»
#include <iostream> using namespace std; int main() { setlocale (LC_ALL, «RUS»); int n, i; double a; FILE *f; //описываем файловую переменную //создаем двоичный файл в режиме записи f=fopen(«D:\\game\\noobs.dat», «wb»); //ввод числа n cout<<«n=»; cin>>n; fwrite(&n, sizeof(int), 1, f); //цикл для ввода n вещественных чисел for (i=0; i<n; i++) { //ввод очередного вещественного числа cout<<«a=»; cin>>a; //запись вешественного числа в двоичный файл fwrite(&a, sizeof(double), 1, f); } //закрываем файл fclose(f); system(«pause»); return 0; } |
Задача 2
Вывести на экран содержимого созданного в прошлой задаче двоичного файла D:\\game\\noobs.dat
Решение:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#include «stdafx.h»
#include <iostream> using namespace std; int main() { setlocale (LC_ALL, «RUS»); int n, i; double *a; FILE *f; //описываем файловую переменную //открываем существующий двоичный файл в режиме чтения f=fopen(«D:\\game\\noobs.dat», «rb»); //считываем из файла одно целое число в переменную n fread(&n, sizeof(int), 1, f); //вывод n на экран cout<<«n=»<<n<<endl; //выделение памяти для массива из n чисел a=new double[n]; //чтение n вещественных чисел из файла в массив a fread(a, sizeof(double), n, f); //вывод массива на экран for (i=0; i<n; i++) cout<<a[i]<<«\t«; cout<<endl; //закрываем файл fclose(f); system(«pause»); return 0; } |
Двоичный файл — последовательная структура данных, после открытия файла доступен первый байт, хранящийся в нем. Можно последовательно записывать или считывать данные из файла. Допустим, необходимо считать пятнадцатое число, а затем первое. С помощью последовательного доступа это можно сделать следующим способом:
1
2 3 4 5 6 7 8 9 10 |
int n, i;
double a; FILE *f; f=fopen(«D:\\game\\noobs.dat», «rb»); for (i=0; i<15; i++) fread(&a, sizeof(double), 1, f); fclose(f); f=fopen(«D:\\game\\noobs.dat», «rb»); fread(&a, sizeof(double), 1, f); fclose(f); |
Как видно, такое чтение чисел из файла, а затем повторное открытие файла — не самый удобный способ. Гораздо удобнее будет использовать функцию fseek перемещения указателя файла к заданному байту.
int fseek(FILE *filename, long int offset, int origin);
Функция устанавливает указатель текущий позиции файла F в соответствии со значением начала отсчета origin и смещения offset. Параметр offset равен количеству байтов, на которые будет смещен указатель файла относительно начала отсчета, заданного параметром origin. В качестве значения для параметра origin должно быть взято одно из следующих значений отсчета смещения offset, определенных в заголовке stdio.h:
- SEEK_SET — с начала файла;
- SEEK_CUR — с текущей позиции;
- SEEK_END — с конца файла.
Функция возвращает нулевое значение при успешном выполнение операции, ненулевое — при возникновении сбоя при выполнении смещения
Функция fseek фактически реализует прямой доступ к любому значению в файле. Необходимо только знать месторасположение (номер байта) значения в файле. Рассмотрим использование прямого доступа в двоичных файлах на примере решения следующей задачи.
Задача 3
В созданном раннее двоичном файле D:\\game\\noobs.dat, поменять местами наибольшее и наименьшее из вещественных чисел.
Алгоритм решения задачи состоит из следующих этапов:
- чтение вещественных из файла в массив a.
- поиск в массиве а максимального (max) и минимального (min) значения и их номеров (imax, imin).
- перемещения указателя файла к максимальному значению и запись min.
- перемещения указателя файла к минимальному значению и запись max.
Ниже приведен текст программы решения задачи с комментариями.
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
#include «stdafx.h»
#include <iostream> using namespace std; int main() { setlocale (LC_ALL, «RUS»); int n, i, imax, imin; double *a, max, min; FILE *f; //открытие файла в режиме чтения и записи f=fopen(«D:\\game\\noobs.dat», «rb+»); //считываем из файла в переменную n количество //вещественных чисел в файле fread(&n, sizeof(int), 1, f); cout<<«n=»<<n<<endl; //выделяем память для хранения вещественных чисел, //которые будут храниться в массиве a a=new double[n]; //считываем из файла в массив а вещественные числа fread(a, sizeof(double), n, f); //поиск максимального и минимального элементов //в массиве а и их индексов for (imax=imin=0, max=min=a[0], i=1; i<n; i++) { if (a[i]>max) { max=a[i]; imax=i; } if (a[i]<min) { min=a[i]; imin=i; } } //перемещение указателя к максимальному элементу fseek(f, sizeof(int)+imax*sizeof(double), SEEK_SET); //запись min вместо максимального элемента файла fwrite(&min, sizeof(double), 1, f); //перемещение указателя к минимальному элементу fseek(f, sizeof(int)+imin*sizeof(double), SEEK_SET); //запись max вместо минимального элемента файла fwrite(&max, sizeof(double), 1, f); //закрытие файла fclose(f); //освобождение памяти delete []a; system(«pause»); return 0; } |
Итак, мы рассмотрели основные принципы работы с файлами в C++. В следующих уроках они вам еще встретятся, поэтому усвойте их как можно лучше.