Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Рацеев С.М. Программирование на языке Си.pdf
Скачиваний:
366
Добавлен:
23.03.2016
Размер:
1.65 Mб
Скачать

while (c != EOF)

{

n = 0;

while (c != EOF && c == x)

{

n++;

c = fgetc(f);

}

if (n > 0) fputc(x, g);

while (c != EOF && c != x)

{

fputc(c, g); c = fgetc(f);

}

}

fclose(f);

fclose(g); return 0;

}

13.3. Двоичные файлы

Двоичный файл обычно состоит из последовательности записей одинаковой длины и одинакового внутреннего формата, причем записи непрерывно следуют друг за другом.

Двоичный формат означает, что числа сохраняются во внутреннем формате. Для символа двоичное представление совпадает с его текстовым представлением (двоичное представление ASCII кода символа). Для чисел же их двоичное представление очень сильно отличается от их текстового представления. Например, число 123 в двоичной системе имеет представление 1111011 и помещается в один байт памяти. В текстовом же формате данное число занимало бы 3 байта памяти.

Для записи и чтения данных в двоичном формате используются соответственно функции fwrite() и fread(). Записав данные с

218

помощью fwrite(), можно возвратить эти данные с помощью fread(). Прототипы данных функций следующие:

size_t fwrite(void *ptr, size_t size, size_t n, FILE *f) size_t fread(void *ptr, size_t size, size_t n, FILE *f)

Функция fwrite() записывает в файл f из массива, указанного в переменной ptr, n элементов, размер которых указан параметром size. Данная функция возвращает количество успешно записанных элементов.

Функция fread() считывает из файла f в массив, указанный в переменной ptr, не более n элементов, размер которых указан параметром size. Данная функция возвращает количество успешно считанных элементов.

Если требуется, например, записать в двоичный файл f значение переменной x типа double, то это можно сделать таким образом:

fwrite(&x, sizeof(x), 1, f);

Если же требуется записать в файл массив целых чисел a, содержащий n элементов, то это можно сделать следующим образом:

fwrite(a, sizeof(int), n, f);

Для задания того, что файл открыт в двоичном режиме, следует добавить к значению режима открытия символ ‘b’: “rb”, “wb”, “ab”, “r+b”, “w+b”, “a+b”. Рассмотрим примеры работы с двоичными файлами.

Пример 1. Заполним двоичный файл целыми числами.

int CreateFile(char *fileName)

{

FILE *f; int a;

if ((f = fopen(fileName, "wb")) == NULL) return 1;

printf("a = "); scanf("%d", &a); while (a != 0)

{

fwrite(&a, sizeof(a), 1, f); printf("a = "); scanf("%d", &a);

}

219

fclose(f); return 0;

}

Пример 2. Чтение файла целых чисел, созданного в предыдущем примере.

int ReadFile(char *fileName)

{

FILE *f; int a;

if ((f = fopen(fileName, "rb")) == NULL) return 1;

while (fread(&a, sizeof(a), 1, f)) printf("a = %d\n", a);

fclose(f); return 0;

}

Пример 3. Следующая функция Size() возвращает количество байтов, занимаемых файлом с именем fileName. Если такого файла не существует, тогда функция возвращает значение -1.

long Size(char *fileName)

{

FILE *f; long n;

if ((f = fopen(fileName, "rb")) == NULL) return -1;

fseek(f, 0, SEEK_END); /* перемещаем указатель а конец файла */ n = ftell(f); /* считываем текущую позицию указателя */ fclose(f);

return n;

}

Пример 4. Чтение двоичного файла целых чисел в обратном порядке.

220

int ReadConverseFile(char *fileName)

{

FILE *f; int a; long i, n;

if ((f = fopen(fileName, "rb")) == NULL) return 1;

n = Size(fileName)/sizeof(int); /* количество компонент в файле */ for (i = n - 1; i >= 0; i--)

{

fseek(f, i*sizeof(int), SEEK_SET); fread(&a, sizeof(a), 1, f);

printf("a = %d\n", a);

}

fclose(f); return 0;

}

Пример 5. Требуется заменить все элементы двоичного файла целых чисел на их квадраты.

int SquareRechange(char *fileName)

{

FILE *f; long i, n; int a;

if ((f = fopen(fileName, "r+b")) == NULL) return 1;

n = Size(fileName)/sizeof(int); for (i = 0; i < n; i++)

{

fseek(f, i*sizeof(a), SEEK_SET); fread(&a, sizeof(a), 1, f);

a *= a;

fseek(f, i*sizeof(a), SEEK_SET); fwrite(&a, sizeof(a), 1, f);

}

221

fclose(f); return 0;

}

Функция fwrite() позволяет записывать в файл целые структуры, которые затем можно прочитать с помощью fread().

Пример 6. Пусть имеются сведения о работниках некоторой организации: фамилия работника, год рождения, заработная плата. Объединим перечисленные элементы данных в структуру

WORKER:

struct WORKER

 

 

{

 

 

char name[20];

/* фамилия

*/

int year;

/* год рождения

*/

float earnings;

/* заработная плата */

};

 

 

Чтобы записать на диск очередные сведения о рабочем (очередную структуру), используем такую инструкцию:

fwrite(&worker, sizeof(worker), 1, f);

где переменная worker имеет тип WORKER. Аналогично, чтобы считать очередную структуру, воспользуемся инструкцией

fread(&worker, sizeof(worker), 1, f);

В приведенной ниже программе функция CreateFile() заполняет файл сведений о работниках, а функция ReadFile() выводит содержимое файла на экран.

#include<stdio.h> struct WORKER

{

char name[20]; int year;

float earnings; };

222

/* заполнение файла */

int CreateFile(char *fileName)

{

FILE *f;

struct WORKER worker;

if ((f = fopen(fileName, "wb")) == NULL) return 1;

printf("name: "); scanf("%s", worker.name);

while (strcmp(worker.name, "000"))

{

printf("year: "); scanf("%d", &worker.year); printf("earnings: ");

scanf("%f", &worker.earnings);

fwrite(&worker, sizeof(worker), 1, f); /* запись структуры в файл */ printf("name: ");

scanf("%s", worker.name);

}

fclose(f); return 0;

}

/* чтение файла */

int ReadFile(char *fileName)

{

FILE *f;

struct WORKER worker;

if ((f = fopen(fileName, "rb")) == NULL) return 1;

while (fread(&worker, sizeof(worker), 1, f))

{

printf("%s ", worker.name); printf("%d ", worker.year); printf("%.2f\n", worker.earnings);

}

223

fclose(f); return 0;

}

int main( )

{

char *fileName = "c:\\a.data"; CreateFile(fileName); ReadFile(fileName);

return 0;

}

Пример 7. Иногда требуется просто добавить одну запись в конец файла. Поэтому можно записать функцию заполнения файла из предыдущего примера в следующем виде.

/* функция добавления записи в конец файла f */

int AddWorker(FILE *f, const struct WORKER *worker)

{

fseek(f, 0, SEEK_END); /* перемещаем указатель в конец файла f */ fwrite(worker, sizeof(*worker), 1, f);

if (ferror(f)) return 1; else return 0;

}

/* заполнение файла */

int CreateFile(char *fileName)

{

FILE *f;

struct WORKER worker;

if ((f = fopen(fileName, "wb")) == NULL) return 1;

printf("name: "); scanf("%s", worker.name);

while (strcmp(worker.name, "000"))

{

224

printf("year: "); scanf("%d", &worker.year); printf("earnings: ");

scanf("%f", &worker.earnings);

AddWorker(f, &worker); /* добавляем запись в файл */ printf("name: ");

scanf("%s", worker.name);

}

fclose(f); return 0;

}

Пример 8. Очень часто приходится копировать файлы. Рассмотрим быстрый алгоритм копирования файлов с использованием буфера обмена. Ниже приводится функция CopyFile(), которая копирует содержимое файла fileNameIn в файл fileNameOut.

#define BUFSIZE 1024 /* размер буфера */

int CopyFile(const char *fileNameIn, const char *fileNameOut)

{

FILE *in, *out;

char buffer[BUFSIZE]; long n;

if ((in = fopen(fileNameIn, "rb")) == NULL) return 1;

if ((out = fopen(fileNameOut, "wb")) == NULL)

{

fclose(in); return 1;

}

while (n = fread(buffer, sizeof(char), BUFSIZE, in)) fwrite(buffer, sizeof(char), n, out);

fclose(in);

fclose(out); return 0;

}

225