Двоичный файл это последовательность
данных не текстового формата. Поэтому редактировать файл в текстовом редакторе
невозможно. С другой стороны такой файл может иметь меньший объем, а для
редактирования могут быть предназначены специальные редакторы.
Чтение и запись потока байтов выполняют функции fread и fwrite.
fread(void *buffer,
size, count, FILE *f);
Функция считывает count элементов длиной size байтов в буфер, заданный указателем
buffer, из потока f.
Функция возвращает количество прочитанных
элементов, которое может быть меньше count, если при чтении произошла ошибка или встретился конец
файла.
fwrite(const void
*p, size, n, FILE *f);
Функция записывает n элементов длиной size байт из буфера, заданного
указателем р, в поток f.
Возвращает число записанных элементов.
Пример, демонстрирующий работу с этими функциями:
struct Client
{
int Num;
char SurName[27];
char Name[21];
char SecName[21];
};
FILE *stream;
Client AClient,
RClient;
//Открываем файл для вывода
if ((stream =
fopen("d:\\SAMPLE.DAT", "wb")) == NULL)
{
printf(RUS("Файл не открыт для
записи\n"));
getch();
return 1;
}
AClient.Num = 1;
strcpy(AClient.SurName,"Petrov");
strcpy(AClient.Name,
"Petr");
strcpy(AClient.SecName,
"Petrovich");
//Запись структуры в файл
fwrite(&AClient,
sizeof(AClient), 1, stream);
//Закрываем файл
fclose (stream) ;
//Открываем файл для чтения
if ((stream = fopen
("d:\\SAMPLE.DAT ", "rb") ) == NULL)
{
printf (RUS("Файл не открыт для
чтения\n")) ;
getch();
return 2 ;
}
fread(&RClient,
sizeof (RClient) , 1 , stream) ;
//Закрываем файл
fclose (stream) ;
printf ("The
structure contains : \n ");
printf ("Num =
%d SurName = %s Name = %s SecName = %s",
RClient . Num ,
RClient . SurName , RClient . Name , RClient . SecName
) ;
В этом примере вначале файл открывается
для записи в него значений полей из структуры AClient, затем этот файл открывается для
чтения содержащейся в нем информации в структуру RClient. После чего поля этой структуры
выводятся на экран. При выполнении программа выводит на экран:
The structure
contains:
Num = 1 SurName =
Petrov Name = Petr SecName = Petrovich
Операции ввода/вывода выполняются,
начиная с текущей позиции потока, определяемой положением (значением) указателя
потока. Указатель устанавливается при открытии на начало или конец файла (в
соответствии с режимом открытия ²a² ,²a+²) и изменяется
автоматически после каждой операции ввода/вывода. Текущее положение указателя
можно получить с помощью функций ftell и fgetpos
и задать явным образом с помощью функций fseek, fsetpos
и rewind. Эти функции
нельзя использовать для стандартных потоков.
long int ftell(FILE *f);
Функция возвращает текущую позицию в файле, связанном с потоком f, как длинное целое. В
случае ошибки она возвращает –1.
int fgetpos(FILE *f, fpos_t *pos);
Функция возвращает текущую позицию в файле, связанном с потоком f, и копирует значение по
адресу pos. Это
значение позднее может использоваться функцией fsetpos. Возвращаемое значение имеет тип
fpos_t.
int fseek(FILE *f,
long off, int org);
Функция перемещает текущую позицию в файле, связанном с потоком f, на позицию off, отсчитываемую от
значения org, которое
должно быть равно одной из трех констант, определенных в <stdio.h>:
SEEK_CUR ( =1 ) – от текущей
позиции указателя;
SEEK_END ( =2 ) – от конца файла;
SEEK_SET ( =0 ) – от начала файла.
Функция возвращает 0 , если указатель текущей позиции в файле успешно
изменен, и отличное от 0 значение в противном случае.
int fsetpos(FILE
*f, const fpos_t *pos);
Функция перемещает текущую позицию в файле, связанном с потоком f, на позицию *pos, предварительно
полученную с помощью функции fgetpos.
void rewind(FILE *f);
Функция очищает флаги ошибок в потоке f и устанавливает текущую позицию на начало
файла.
Функции позиционирования позволяют провести вывод непосредственно
после ввода, не закрывая файл. Для этого их записывают между функциями ввода и
вывода. Однако рекомендуется всегда явным образом закрывать потоки, открытые
для записи, чтобы избежать потери данных.
Рассмотрим пример, демонстрирующий работу этих функций:
struct Client
{
int Num;
char SurName[27];
char Name[21];
char SecName[21];
};
FILE *stream;
Client AClient,
RClient;
//Открываем файл для вывода
if ((stream =
fopen("d:\\SAMPLE.DAT", "wb")) == NULL)
{
printf(RUS("Файл не открыт для
записи\n"));
getch();
return 1;
}
AClient.Num = 1;
strcpy(AClient.SurName,"Petrov");
strcpy(AClient.Name,
"Petr");
strcpy(AClient.SecName,
"Petrovich");
//Запись структуры в файл
fwrite(&AClient,
sizeof(AClient), 1, stream);
long int pos =
ftell(stream);
//Выводим позицию файла и длину структуры
printf("The
file pos = %d structure length = %d\n", pos, sizeof(AClient));
//Репозиционируем файл
rewind(stream);
//Открываем файл для чтения
if ((stream = fopen
("d:\\SAMPLE.DAT ", "rb") ) == NULL)
{
printf (RUS("Файл не открыт для
чтения\n")) ;
getch();
return 2 ;
}
fread(&RClient,
sizeof (RClient) , 1 , stream) ;
//Закрываем файл
fclose (stream) ;
printf ("The
structure contains : \n ");
printf ("Num =
%d SurName = %s Name = %s SecName = %s",
RClient . Num ,
RClient . SurName , RClient . Name , RClient . SecName
) ;
Этот пример представляет собой
модификацию предыдущего примера. Здесь файл открывается лишь однажды, и после
записи в него структуры на экран выводится значение указателя позиции и длины
структуры. При выполнении программа выводит на экран:
The file pos
= 76 structure length
= 76
The structure
contains:
Num = 1 SurName =
Petrov Name = Petr SecName = Petrovich
Допустим, что в файле хранятся сведения о
мониторах. В каждой строке указан тип, оптовая и розничная цены и примечание.
Для простоты данные в каждой строке записаны единообразно: первые 20 символов
занимает тип монитора, далее по 5 символов целые числа, представляющие оптовую
и розничную цены, затем примечание длиной не более 40 символов.
Приведенная ниже программа построчно
считывает данные из текстового файла в буферную переменную s, затем формирует из них структуру mon и записывает ее в двоичном
режиме в выходной файл. Далее производится считывание из этого файла
произвольной записи.
FILE *fi, *fo;
if((fi =
fopen("d:\\file.txt", "r")) == 0){
cout
<< "Ошибка открытия входного файла"; return 1;}
if((fo =
fopen("d:\\binfile.out", "w+b")) == 0){
cout
<< "Ошибка открытия выходного файла"; return 1;}
const int dl = 80;
char s[dl];
struct{
char type[20];
int opt, rozn;
char comm[40];
}mon;
int kol
= 0; // Количество записей в файле
while (fgets(s, dl, fi)) // Преобразование строки в структуру:
{
strncpy(mon.type,
s, 19);
mon.type[19]='\0';
mon.opt =
atoi(&s[20]);
mon.rozn =
atoi(&s[25]);
strncpy(mon.comm,
&s[30], 40);
fwrite(&mon,
sizeof mon, 1, fo);
kol++;
}
fclose(fi);
int i;
cout
<< RUS("\nВведите номер записи
");
cin >>
i; // Номер записи
if (i >= kol) {cout << "Запись не существует"; return 1;}
// Установка указателя текущей позиции файла на запись i:
fseek(fo, (sizeof
mon)*i , SEEK_SET);
fread(&mon,
sizeof mon, 1, fo);
cout <<
"mon. type " << mon.type << " opt " <<
mon.opt
<< "
rozn " << mon.rozn << endl ;
fclose(fo);
|