|
Попробуйте часть кода до слова main заменить на #include "stdafx.h" //1 #include <iostream> //2 using namespace std; //3 |
Работа с файлами
10.1.2. Двоичные файлы
Двоичные файлы отличаются от текстовых тем, что представляют собой последовательность байтов, содержимое которых может иметь различную природу. Это могут быть байты, представляющие числовую информацию в машинном формате, байты с графическими изображениями, байты с аудиоинформацией и т.п. Содержимое таких байтов может случайно совпасть с управляющими кодами таблицы ASCII, но на них нельзя реагировать так, как это делается при обработке текстовой информации. Естественно, что единицей обмена с такими данными могут быть только порции байтов указанной длины.
Создание двоичных файлов с помощью функции fopen отличается от создания текстовых файлов только указанием режима обмена – "rb" (двоичный для чтения), "rb+" (двоичный для чтения и записи), "wb" (двоичный для записи), "wb+" (двоичный для записи и чтения):
FILE *f1; ......... f1=fopen(имя_файла, "режим");
Обычно для обмена с двоичными файлами используются функции fread и fwrite:
c_w = fwrite(buf, size_rec, n_rec, f1);
Здесь
- buf – указатель типа void* на начало буфера в оперативной памяти, из которого информация переписывается в файл;
- size_rec – размер передаваемой порции в байтах;
- n_rec – количество порций, которое должно быть записано в файл;
- f1 – указатель на блок управления файлом;
- c_w – количество порций, которое фактически записалось в файл.
Считывание данных из двоичного файла осуществляется с помощью функции fread с таким же набором параметров:
c_r = fread(buf, size_rec, n_rec, f1);
Здесь
- c_r – количество порций, которое фактически прочиталось из файла;
- buf – указатель типа void* на начало буфера в оперативной памяти, в который информация считывается из файла.
Обратите внимание на значения, возвращаемые функциями fread и fwrite. В какой ситуации количество записываемых порций может не совпасть с количеством записавшихся данных? Как правило, на диске не хватило места, и на такую ошибку надо реагировать. А вот при чтении ситуация, когда количество прочитанных порций не совпадает с количеством запрашиваемых порций, не обязательно является ошибкой. Типичная картина – количество данных в файле не кратно размеру заказанных порций.
Двоичные файлы допускают не только последовательный обмен данными. Так как размеры порций данных и их количество, участвующее в очередном обмене, диктуются программистом, а не смыслом информации, хранящейся в файле, то имеется возможность пропустить часть данных или вернуться повторно к ранее обработанной информации. Контроль за текущей позицией доступных данных в файле осуществляет система с помощью указателя, находящегося в блоке управления файлом. С помощью функции fseek программист имеет возможность переместить этот указатель:
fseek(f1,delta,pos);
Здесь
- f1 – указатель на блок управления файлом;
- delta – величина смещения в байтах, на которую следует переместить указатель файла;
- pos – позиция, от которой производится смещение указателя (0 или SEEK_SET – от начала файла, 1 или SEEK_CUR – от текущей позиции, 2 или SEEK_END – от конца файла)
Кроме набора функций { fopen/fclose, fread/fwrite } для работы с двоичными файлами в библиотеке BC предусмотрены и другие средства – _dos_open /__dos_close, _dos_read /_dos_write, _create /_close, _read /_write. Однако знакомство со всеми возможностями этой библиотеки в рамках настоящего курса не предусмотрено.
Пример 2. Рассмотрим программу, которая создает двоичный файл для записи с именем c_bin и записывает в него 4*10 порций данных в машинном формате (строки, целые и вещественные числа). После записи данных файл закрывается и вновь открывается для чтения. Для демонстрации прямого доступа к данным информация из файла считывается в обратном порядке – с конца. Контроль записываемой и считываемой информации обеспечивается дублированием данных на экране дисплея.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
main( )
{ FILE *f1; //указатель на блок управления файлом
int j,k;
char s[]="Line";
int n;
float r;
f1=fopen("c_bin","wb"); //создание двоичного файла для записи
for(j=1;j<11;j++)
{ r=sqrt(j);
fwrite(s,sizeof(s),1,f1); //запись строки в файл
fwrite(&j,sizeof(int),1,f1); //запись целого числа в файл
fwrite(&r,sizeof(float),1,f1); //запись вещественного числа
printf("\n%s %d %f",s,j,r); //контрольный вывод
}
fclose(f1); //закрытие файла
printf("\n");
f1=fopen("c_bin","rb"); //открытие двоичного файла для чтения
for(j=10; j>0; j--)
{//перемещение указателя файла
fseek(f1,(j-1)*(sizeof(s)+sizeof(int)+sizeof(float)),SEEK_SET);
fread(&s,sizeof(s),1,f1); //чтение строки
fread(&n,sizeof(int),1,f1); //чтение целого числа
fread(&r,sizeof(float),1,f1); //чтение вещественного числа
printf("\n%s %d %f",s,n,r); //контрольный вывод
}
getch();
return 0;
}
//=== Результат работы ===
Line 1 1.000000
Line 2 1.414214
Line 3 1.732051
Line 4 2.000000
Line 5 2.236068
Line 6 2.449490
Line 7 2.645751
Line 8 2.828427
Line 9 3.000000
Line 10 3.162278
Line 10 3.162278
Line 9 3.000000
Line 8 2.828427
Line 7 2.645751
Line 6 2.449490
Line 5 2.236068
Line 4 2.000000
Line 3 1.732051
Line 2 1.414214
Line 1 1.000000
10.2.
Использованные в этом примере операторы:
fclose(f1); //закрытие файла
f1=fopen("c_bin","rb"); //открытие двоичного файла для чтениямогут быть заменены обращением к единственной функции freopen, которая повторно открывает ранее открытый файл:
f1=freopen("c_bin","rb");Основное правило, которого надо придерживаться при обмене с двоичными файлами звучит примерно так – как данные записывались в файл, так они должны и читаться.
10.1.3. Структурированные файлы
Структурированный файл является частным случаем двоичного файла, в котором в качестве порции обмена выступает структура языка C, являющаяся точным аналогом записи в Паскале. По сравнению с предыдущим примером использование записей позволяет сократить количество обращений к функциям fread/fwrite, т.к. в одном обращении участвуют все поля записи.
Инициализация структурированного файла выполняется точно таким же способом, как и подготовка к работе двоичного файла.
Пример 3. Приведенная ниже программа является модификацией предыдущего примера. Единственное ее отличие состоит в использовании структуры (записи) b, состоящей из символьного ( b.s, 5 байт, включая нулевой байт – признак конца строки), целочисленного ( b.n, 2 байта в BC и 4 байта в BCB) и вещественного ( b.r, 4 байта) полей.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <conio.h>
main( )
{ FILE *f1;
int j,k;
struct {
char s[5];
int n;
float r;
} b;
strcpy(b.s,"Line");
f1=fopen("c_rec","wb");
for(j=1;j<11;j++)
{ b.n=j; b.r=sqrt(j);
fwrite(&b,sizeof(b),1,f1);
printf("\n%s %d %f",b.s,b.n,b.r);
}
fclose(f1);
printf("\n");
f1=fopen("c_rec","rb");
for(j=10; j>0; j--)
{ fseek(f1,(j-1)*sizeof(b),SEEK_SET);
fread(&b,sizeof(b),1,f1);
printf("\n%s %d %f",b.s,b.n,b.r);
}
getch();
}Результат работы этой программы ничем не отличается от предыдущего примера.