4313

Организация файлового ввода-вывода в Си

Контрольная

Информатика, кибернетика и программирование

Организация файлового ввода-вывода в Си Считываемая и записываемая информация с точки зрения пользователя представляет собой некую последовательность байтов. Чтобы отразить эту особенность, при реализации ввода-вывода в Си используется понятие...

Русский

2012-11-16

119.5 KB

26 чел.

Организация файлового ввода-вывода в Си

Считываемая и записываемая информация с точки зрения пользователя представляет собой некую последовательность байтов. Чтобы отразить эту особенность, при реализации ввода-вывода в Си используется  понятие "поток" (stream). Поток – это логическое устройство, являющееся источником или получателем данных. В зависимости от того, откуда поступает считываемая информация или куда направляется записываемая информация, поток связывается с соответствующим устройством ввода вывода (клавиатура, дисплей, принтер и т.п.) или с именованной областью внешней памяти – файлом, если требуется долговременно хранить информацию либо получить доступ к хранимой информации.  

При организации ввода-вывода в С используется буферизация, то есть обмен информацией между программой и внешним устройством происходит не непосредственно, а через буфер – специально выделяемую системой область оперативной памяти. Буферизация  ускоряет работу программы из-за уменьшения количества обращений к внешним устройствам.

В <stdio.h>  описана константа BUFSIZE, величина которой 512:

#define  BUFSIZE        512               

Для изменения размера буфера предназначены функции   setbuf() или  setvbuf().

Стандартная библиотека ввода-вывода языка Си (stdio) поддерживает текстовые и бинарные (двоичные) потоки. Текстовый поток – это последовательность строк, каждая из которых заканчивается символом ‘\n’. Операционная среда может потребовать коррекции текстового потока. Например, при вводе текстового потока система преобразует символы возврат каретки и перевод строки в символ ‘\n’, а при выводе текстового потока в среду операционной системы происходит обратное преобразование. Бинарный поток – это последовательность непреобразуемых байтов, представляющих собой некоторые промежуточные данные, которые обладают тем свойством, что если их записать, а затем прочесть той же системой ввода-вывода, то будет получена информация, совпадающая с исходной.

Поток соединяется с файлом или устройством посредством его открытия; указанная связь разрывается путем закрытия потока. Открытие файла осуществляется  с  помощью  функции fopen, которая в качестве результата возвращает указатель на структуру типа FILE. Этот указатель называют указателем файла, а структуру – файловой структурой. Шаблон файловой структуры описан в заголовочном файле stdio.h . Файловая структура состоит из 9-ти компонент и содержит всю информацию, необходимую для управления потоком (адрес начала буфера файла – buffer; сведения о количестве оставшихся в буфере символов-байт – level; указатель на следующий символ, выводимый из буфера или поступающий в него – curp и т.д.). Указатель файла в дальнейшем используется для ввода и вывода информации в файл. Указатель файла позиционируется в соответствии с открытием потока: если поток открыт для чтения или записи - на начало файла, если для дозаписи - на конец файла. Указатель файла изменяется в соответствии с операцией записи или чтения. После окончания ввода/вывода поток необходимо закрыть с помощью функции fclose, после  чего  указатель файла можно использовать для последующего открытия файла.

При выполнении любой программы автоматически открываются пять стандартных потоков, имеющих следующие указатели файлов: stdin - поток ввода, stdout - поток вывода, stderr  -  поток вывода для сообщений об  ошибках ( для вывода в поток stderr используется функция perror ),  stdaux  -  последовательный порт и stdprn - устройство печати. Первые три потока по умолчанию связываются с консолью. Имена указателей стандартных потоков ввода-вывода могут указываться в функциях ввода-вывода, прототипы  которых описаны в заголовочном файле stdio.h. Для переопределения стандартных потоков используется функция freopen. Также в заголовочном файле stdio.h объявлен   ряд  макроопределений, в том числе NULL – нулевой байт; EOF - символ конца входного потока (целая константа, в DOS ей соответствует нажатие клавиш <Ctrl+Z>); BUFSIZЕ- размер буфера; FILENAME_MAX – константа, задающая ограничение на длину имени файла; FOPEN_MAX – константа, ограничивающая число одновременно открытых файлов.

Открытие и закрытие файла.

Перед открытием файла необходимо объявить указатель на файл:

FILE  * имя_указателя;

Например:     FILE  * in,* out;

Функция fopen открывает файл с заданным именем:

FILE *  fopen (const char *filename, const  char *mode)

 

filename – имя файла или полный путь к нему на диске. Если указано только имя файла, то его поиск осуществляется только в текущем каталоге.

mode – режим открытия файла.

Режим mode допускает следующие значения:

"r"  - чтение существующего файла; если файл не существует – ошибка открытия файла

"w"  - запись в файл (если файл существует, то его содержимое удаляется); если файл не существует, то он будет создан

"a"  - запись в конец  существующего файла (если файл не существует, то он создается)

"r+" - чтения и записи существующего файла; если файл не существует – ошибка открытия файла

"w+" - чтения и перезаписи файла (предыдущая версия файла удаляется); если файл не существует, то он будет создан

"a+" - чтения и записи (дозаписи) файла.

В конец строки записывается t - текстовый режим или b - двоичный режим. Например: "rt" , "w+b". По умолчанию (отсутствуют символы t и b) файл открывается в текстовом режиме.

Если произошла ошибка открытия файла, то функция fopen() возвращает NULL.

Причины возникновения ошибок открытия файла:

  •  файл с указанным именем не существует (возможно, неправильно задано имя файла);
  •  нет места на диске.

Функции закрытия файла:

int  fclose (FILE *stream);        -   закрывает поток stream;

int  fcloseall (void);                   - закрывает все открытые потоки

Возврат при ошибке – EOF, в противном случае - 0.

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


Пример 1.
Открытие (создание) нового  файла

#include<stdio.h>

void main (void)

{   

FILE  *f1, *f2;                                           // Объявление указателей на структуру типа FILE

// Открытие файла test.dat  в текущем каталоге в режиме записи

f1=fopen ("test.dat", "w");

// Открытие файла prim.txt  в режиме чтения

f2=fopen ("c:\\user\\prim.txt", "r");

// Закрытие файлов 

fclose(f1);

fclose(f2);

}

int feof(FILE *stream);  - возвращает нулевое значение, пока не встретился конец указанного в аргументе файла.

int  remove (const char *filename)

Функция удаляет файл с указанным именем. В случае ошибки возвращает ненулевое значение.

int  rename (const char *oldname, const char * newname)

Функция переименовывает файл: 1-й аргумент – старое имя файла, 2-й аргумент – новое имя файла. В случае ошибки возвращает ненулевое значение.

int  fflush(FILE *stream);  

Функция производит дозапись всех оставшихся в буфере еще не записанных данных. При возникновении ошибки возвращает EOF, в противном случае – 0.

 Функции позиционирования файла 

int   fseek(FILE *stream, long offset, int origin)

Функция устанавливает указатель файла в заданную позицию; последующая запись или чтение файла будут производиться с этой позиции.

Позиция устанавливается со смещением offset байт:

- относительно начала файла, если origin равно SEEK_SET (или 0);

- относительно текущей  позиции,  если origin равно SEEK_CUR (или 1);

- относительно конца файла, если origin равно SEEK_END (или 2).

Если значение offset положительно - движение вперед, иначе - движение назад.

Если указатель успешно перемещен, то функция возвращает 0. Возврат при ошибке: не нуль.

Например, пусть f – файловый указатель, тогда

fseek( f, L0, SEEK_END);  - указатель файла устанавливается на конец файла

fseek( f, L0, SEEK_SET);  - указатель файла устанавливается на начало файла

long  ftell(FILE *stream)

Функция возвращает номер текущей позиции от начала файла (смещение в байтах от начала файла). Номер первой позиции равен 0.

void  rewind(FILE *stream)

Функция устанавливает указатель файла на начало файла.

Работа с текстовыми файлами

В зависимости от способа описания, выделяют текстовые и двоичные. Вид файла определяет способ хранения информации в файле.

Текстовый файл представляет собой набор строк произвольной длины, каждая строка заканчивается управляющим символом ‘\n’. Текстовый файл является файлом последовательного доступа. Логически текстовый файл можно представить как именованную последовательность байтов, имеющую начало и конец. Чтение из файла или запись в файл ведется байт за байтом от начала к концу. Если файл открыт в режиме чтения (“r”) или записи (“w”), то перед первым обращением к функциям вода-вывода указатель файла позиционирован на начало файла (первый байт с номером позиции 0). Если файл открыт в режиме дозаписи  в конец файла (“a”), то указатель файла позиционирован на конец файла. После каждого чтения  или записи указатель сдвигается на определенное количество байт. Такой способ доступа к информации называется последовательным. Если запись и чтение производится в один поток (режимы "r+", "w+", "a+"), то при переходах от чтения к записи и обратно используется функция позиционирования указателя на файл fseek().

Текстовый файл может быть создан, прочитан, модифицирован средствами любого текстового редактора. Текстовые файлы переносимы с одного типа компьютера на другой, если символы, содержащиеся в файле, принадлежат стандартному набору символов (т.е. не используются дополнительные символы, такие, например, как символы псевдографики фирмы IBM).

Данные в текстовом файле могут быть организованы как:

1. непрерывный поток символов

2. последовательность строк переменной длины

3. форматированные поля, разделенные определенным символом, т.е. набор слов, чисел определенного типа и пр.

В соответствии со способом организации данных в файле используются те или иные функции файлового ввода-вывода верхнего уровня.

Функции для  посимвольного ввода-вывода

int fgetc(FILE *stream)

int getc(FILE *stream)

Функции fgetc и getc  возвращают следующий символ из потока  stream или EOF, если исчерпан файл или обнаружена ошибка.

int fputc(int c, FILE *stream)

int putc(int c,FILE *stream)                

Функции fputc и putc записывают символ с в поток stream. Возвращают записанный символ или EOF, если обнаружена ошибка.

int ungetc(char c, FILE *stream);         

Функция ungetc возвращает символ с обратно в поток stream. В качестве результата ungetc выдает отправленный назад символ или, в случае ошибки, EOF.

Пример 2. Cоздание копии файла

#include<stdio.h>

#include<stdlib.h>

void main (void)

{   int s;

// Символьные массивы для хранения имен входного и выходного файлов

char file_name_in[20], file_name_out[20];

FILE *in, *out;                                                // Указатели входного и выходного потоков

//Ввод пользователем имени копируемого файла

puts (“Введите имя входного файла: ”);

gets(file_name_in);

// Открытие входного потока

if((in=fopen (file_name,"rt")) == NULL)

   { fprintf (stderr, "невозможно открыть файл %s\n", file_name_in); exit(1); }

//Ввод пользователем имени файла, в который производится копирование

puts (“Введите имя выходного файла: ”);

gets(file_name_out);

//Открытие выходного потока

if((out=fopen(file_name_out,"wt")) == NULL)

  { fprintf(stderr, " невозможно открыть файл %s\n", file_name_out); exit(1); }

// Цикл записи символов из входного потока в выходной

 while( (s=fgetc(in) ) != EOF )

fputc(s, out);

// Закрытие потоков 

fclose(in);

fclose(out);

}

Функции построчного ввода-вывода

char * fgets(char *s, int n, FILE *stream)  

Функция fgets читает не более n-1 символов в массив s из потока stream, прекращая чтение, если встретился символ ‘\n’ (переход на новую строку), который включается в массив; кроме того, в массив записывается признак конца строки ‘\0’. Функция возвращает s или, если исчерпан файл или обнаружена ошибка, NULL.

int fputs(char *s, FILE *stream)  

Функция fputs записывает cтроку s в поток stream. Функция возвращает неотрицательное целое или EOF в случае ошибки.

Функции форматированного ввода-вывода

 int fprintf(FILE *stream, const char *format, <список имен>)

Функция fprintf  осуществляет вывод информации в поток stream под управлением строки форматирования format. Возвращаемое значение – число записанных символов или, в случае ошибки, отрицательное значение.

int  fscanf(FILE *stream, const char *format, <список указателей>)

Функция fscanf  осуществляет ввод информации из потока stream под управлением строки форматирования format. Возвращает число прочитанных символов или EOF в случае исчерпания файла или возникновении ошибки.

Замечание: особенностью форматного чтения данных из файла является то обстоятельство, что необходимо хорошо представлять формат данных, содержащихся в файле!

Пример 3. Форматная запись в файл и форматное чтение из файла

//Запись в файл целых чисел в количестве, указанном пользователем

//Чтение информации из файла с подсчетом количества положительных чисел

#include<stdio.h>

#include<stdlib.h>

#include<conio.h>

void main()

{

FILE *f;        //Объявление файлового указателя

int n,            //Общее кол-во чисел

   np=0,       //Кол-во положительных чисел

   r,              //Буферная переменная

   i;

clrscr();

printf("Сколько чисел хотите записать в файл? ");

scanf("%d",&n);

//Открытие файла одновременно для записи и чтения

if((f=fopen("c:\\user\\rand.txt","w+"))==NULL)

  {puts("Ошибка открытия файла!!!");getch();exit(-1);}

randomize();

for(i=0;i<n;i++)

  {

   r=random(201)-100;

   //Запись в файл очередного случайного числа

   fprintf(f,"%d\n",r);

  }

rewind(f);

for(i=0;i<n;i++)

  {

  fscanf(f,"%d",&r);

  if (r>0) np++;

  }

printf("\nКол-во положительных чисел равно %d",np);

fclose(f);

getch();

}

Пример 4. Запись в файл и чтение из файла данных различных типов

#include <stdio.h>

#include <conio.h>

#include <stdlib.h>

#define  N  3

void main(void)

   {

    int n, i, pr;

    char  file_name[20], str[50], c;

     FILE  *f;       // Объявление указателя на файл

    puts("Введите имя файла: ");

    gets(file_name);

    

    // Открытие нового файла для записи

    if((f=fopen(file_name,"w"))==NULL)

      {

      fprintf(stderr,"Нельзя открыть файл %s для записи",file_name);

      getch(); exit(1);

      }

     

    // Ввод данных с клавиатуры

    for(i=0;i<N;i++)

      {

      // Ввод целого числа с клавиатуры

      puts("Введите целое число");

      scanf("%d", &n);

      // Запись целого числа в файл

      fprintf(f, "%d", n);

      // Ввод символа с клавиатуры

      puts("Введите символ");

      fflush(stdin);                  // Очистка стандартного входного потока

      c=getchar();

      // Запись символа в файл

      putc(c, f);

      // Ввод строки с клавиатуры

      puts("Введите строку");

      fflush(stdin);                     // Очистка стандартного входного потока

      gets(str);

      // Запись строки в файл

      fputs(str,f);

     // Переход на новую строку в файле

      putc('\n', f);

      }

     // Закрытие ранее открытого для записи данных файла

     fclose(f);

     // Чтение данных из файла

     // Открытие созданного файла для чтения

      if ( (f=fopen(file_name,"r"))==NULL)

        {

        fprintf(stderr,"Нельзя открыть файл %s для чтения",file_name);

        getch(); exit(1);

        }

       printf("\n\n Из файла прочитаны следующие данные\n\n");

     

      // Чтение данных из файла, пока не встретится признак конца файла  

       pr=getc(f);                         // Чтение символа из файла

       while( !feof(f) )

         {

         // Если не конец файла,

         // то возвращаем считанный символ обратно в поток ввода

         ungetc(pr,f);

       

         // Чтение целого числа из файла

         fscanf(f,"%d", &n);

         // Вывод целого числа на экран

          printf("целое число: %d\n",n);

         // Чтение символа из файла

         c=getc(f);

         // Вывод символа на экран

         printf("символ: %c", c);

         // Чтение строки из файла

         fgets(str, 50, f);

         //вывод строки на экран

         printf("\nстрока: ");

         puts(str);          

         pr=getc(f);       // Чтение символа из файла

         }

       // Закрытие ранее открытого для чтения файла

       fclose(f);

       getch();

       }


Пример 5.
Работа с текстовым файлом, хранящим записи (структуры)

//В текстовом файле хранятся результаты экзаменов в следующем формате:

//каждая запись с информацией об одном студенте хранится в отдельной строке;

//под фамилию отводится 15 позиций (дополняется пробелами),

//затем оценки по трем предметам через пробел

//Требуется вывести на экран фамилию студента,

//имеющего максимальный средний балл  

#include<stdio.h>

#include<string.h>

#include<stdlib.h>

#include<conio.h>

//Структура для хранения информации о студенте

struct w{

        char fam[16];

        int oc[3];

        float sr;

       };

void main()

{

FILE *f;

w wed;

int i;

float max=0,                    //Максимальный средний балл

     sr;                             //Текущий средний балл

char fam_max[15];      //Фамилия студента, имеющего максимальный средний балл

clrscr();

//Открытие файла для чтения

if((f=fopen("c:\\user\\wed.txt","r"))==NULL)

  {puts("Ошибка открытия файла!!!");getch();exit(-1);}

//Цикл чтения записей из файла

while(fgets(wed.fam,16,f)!=NULL)

{ sr=0;

//Подсчет среднего балла

for(i=0;i<3;i++)

   {

    fscanf(f,"%d",&wed.oc[i]);

    sr+=wed.oc[i];

   }

wed.sr=sr/3;

if(wed.sr>max)

  {

   max=wed.sr;

   strcpy(fam_max,wed.fam);

  }

}

if (max) printf("%s %.2f",fam_max,max);

   else  printf("В файле нет данных");

fclose(f);

getch();

}


Работа с двоичными файлами

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

Данные, записываемые в двоичный файл, сохраняются в файле в виде набора символов. Поэтому, можно сказать, что двоичные файлы – это последовательность значений типа char. Использование двоичных файлов делает программы немобильными при переносе из одной среды в другую, поскольку, несмотря на то, что любой набор данных может быть представлен как набор символов, это представление может изменяться при переходе от одной реализации Си к другой. Кроме того, двоичные файлы нельзя создать и прочесть с помощью текстового редактора. Они создаются только в процессе работы программы. В силу вышеуказанных причин достаточно часто информацию хранят в текстовых файлах, на базе которых в процессе выполнения программы создают двоичные файлы и работают с ними, поскольку обработка двоичных файлов также проста, как и обработка массивов. Однако, способ хранения числовой информации в двоичных файлах имеет то преимущество, что позволяет экономить память.

Открытие двоичного файла производится также как и открытие текстового файла - с помощью функции fopen(). Однако требуется обязательно явно указать, что файл открывается в бинарном режиме, для чего в конец строки,  задающей режим открытия файла, добавляется символ ‘b’. Чтение двоичного файла и запись в двоичный файл можно производить только в бинарном режиме (“rb”, “wb” и т.п.).

Например,  

f1=fopen ("test.dat", "wb");   -  открытие двоичного файла test.dat  в текущем каталоге в режиме записи

Закрытие двоичного файла осуществляет функция fclose().

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

int  fread(void *bufer, int size, int count, FILE *stream)

Функция читает count элементов длины size из входного потока stream и помещает в bufer.

int  fwrite(char *bufer, int size, int count, FILE *stream)

Функция дописывает count элементов длины size из области bufer в поток stream.

Можно считать структуру из файла целиком с помощью функции fread, а записать –  с помощью функции fwrite:

fread ( адрес структурной переменной,  размер структуры,

              количество структур, читаемых за  1 раз, указатель на файл);

fwrite ( адрес структуры в памяти,  размер структуры,  

               количество структур, записываемых за  1 раз, указатель на файл);

Пример 6. Создание и чтение двоичного файла, хранящего целые числа,

сгенерированные случайным образом

#include<stdio.h>

#include<conio.h>

#include<stdlib.h>

void main()

{FILE *in;                                       //Объявление файлового указателя

char file_name[50]="c:\\user\\prim.dat";

int a,                                              //Буферная переменная

n,                                        //Кол-во генерируемых целых чисел

i;

clrscr();

printf("Введите кол-во чисел: ");

scanf("%d",&n);

//Открытие двоичного файла одновременно для чтения и записи

in=fopen(file_name,"w+b");

randomize();

//Цикл генерации случайных значений и запись их в файл

for(i=0;i<n;i++)

  {a=random(21)-10;

 fwrite(&a,sizeof(a),1,in);      //Запись одного числа в файл

  }

//Установка указателя на начало файла для чтения

rewind(in);

//Чтение первого числа из файла

printf("\nСодержимое двоичного файла %s\n",file_name);

fread(&a,sizeof(a),1,in);

//Цикл чтения информации из двоичного файла

while(!feof(in))

 {

  printf("%d ",a);

  fread(&a,sizeof(a),1,in);

 }

fclose(in);

getch();

}


Пример 7.
 Запись в двоичный файл вещественных чисел, вводимых

с клавиатуры. Поиск максимального числа в файле

#include<stdio.h>

#include<conio.h>

void main()

{FILE *in;                             //Объявление файлового указателя

char file_name[50]="c:\\user\\prim2.dat";

float a,                                 //Буферная переменная

     max;                              //Максимальное число

clrscr();

//Открытие двоичного файла одновременно для чтения и записи

in=fopen(file_name,"w+b");

//Запись в двоичный файл вещественных чисел, вводимых с клавиатуры

printf("Введите число: ");

scanf("%f",&a);                            //Ввод с клавиатуры первого числа

while(!feof(stdin))

{fwrite(&a,sizeof(a),1,in);  //Запись одного числа в файл

 printf("Введите число: ");

scanf("%f",&a);                 //Ввод с клавиатуры очередного числа

}

rewind(in);                               //Установка указателя на начало файла

//Поиск максимального числа в файле

//Одновременно содержимое файла выводится на экран

printf("\nСодержимое двоичного файла %s\n",file_name);

fread(&a,sizeof(a),1,in);                   //Чтение первого числа из файла

max=a;                               //Первоначально считаем максимальным первое число

while(!feof(in))                  //Пока не конец файла

 {if(a>max) max=a;          //Найдено очередное максимальное число

  printf("%6.2f ",a);    

  fread(&a,sizeof(a),1,in);  //Чтение следующего числа из файла

 }

printf("\n\nМаксимальное число в файле  %.2f",max);

fclose(in);

getch();

}


Пример 7.
  В двух текстовых файлах содержится информация о студентах

                  Информация о каждом студенте хранится в отдельной строке

Структура записей в первом файле следующая:

фамилия (15 символов, дополняется пробелами),

имя (12 символов, дополняется пробелами),

курс и три оценки - по физике, математике и программированию

(номер курса и каждая оценка отделены друг от друга пробелами)

Структура записей во втором файле следующая:

фамилия (15 символов, дополняется пробелами),

имя (12 символов, дополняется пробелами),

пол (буква "ж" или "м") и год рождения через пробел

Сформировать на основе каждого текстового файла соответствующий ему по информационному содержанию двоичный файл. Отсортировать записи в двоичных файлах, расположив фамилии по алфавиту. Определить, кто лучше сдал математику - юноши или девушки,-

#include<stdlib.h>

#include<conio.h>

#include<stdio.h>

#include<string.h>

//Шаблон структуры для хранения записей из первого файла

struct stud1{

char fam[16];

char name[13];

int kurs;

int oc[3];

};

//Шаблон структуры для хранения записей из второго файла

struct stud2{

char fam[16];

char name[13];

char pol;

int god;

};

void main()

{

int i,

   fl,               //Флаг для сортировки

   kolm,         //Кол-во девушек

   kolw;         //Кол-во юношей

float srm,      //Средний балл юношей по математике

     srw;        //Средний балл девушек по математике

long ft;

FILE *ft1,       //Указатель первого текстового файла 

    *ft2,         //Указатель второго текстового файла

    *fd1,        //Указатель первого двоичного файла

    *fd2;        //Указатель второго двоичного файла

//Буферные структуры

stud1 so1, so2;   

stud2 sx1, sx2;

char fnamet1[30]="c:\\user\\oc.txt",

    fnamet2[30]="c:\\user\\xarakt.txt",

    fnamed1[30]="c:\\user\\oc.dat",

    fnamed2[30]="c:\\user\\xarakt.dat";

clrscr();

//Открытие текстовых файлов для чтения

if((ft1=fopen(fnamet1,"r"))==NULL)

 {

  printf("file %s ne syshestvyet",fnamet1);

  getch();exit(-1);

 }

if((ft2=fopen(fnamet2,"r"))==NULL)

 {

  printf("file %s ne syshestvyet",fnamet1);

  getch();exit(-1);

 }

//Открытие двоичных файлов одновременно для записи и чтения

fd1=fopen(fnamed1,"w+b");

fd2=fopen(fnamed2,"w+b");

//Цикл считывания информации из текстовых файлов в буферные структуры

//и записи этих структур в двоичные файлы

while(fgets(so1.fam,16,ft1)!=NULL)    //Считывается фамилия из 1-го текст. файла    

   {fgets(so1.name,13,ft1);                  //Считывается имя из 1-го текст. файла

    fscanf(ft1,"%d",&so1.kurs);           //Считывается номер курса

 //Цикл чтения оценок

    for(i=0;i<3;i++)                 

       fscanf(ft1,"%d",&so1.oc[i]);

    fscanf(ft1,"\n");                                     //Переход на новую стоку в 1-м файле

    fwrite(&so1,sizeof(so1),1,fd1);           //Запись структуры в 1-й двоичн. файл

    fgets(sx1.fam,16,ft2);                  //Считывается фамилия из 2-го текст. файла

    fgets(sx1.name,13,ft2);              //Считывается имя из 1-го текст. файла

    sx1.pol=fgetc(ft2);                     //Считывается пол

    fscanf(ft2, " %d",&sx1.god);     //Считывается год рождения

    fscanf(ft2,"\n");                          //Переход на новую стоку во 2-м файле

    fwrite(&sx1,sizeof(sx1),1,fd2);  //Запись структуры во 2-й двоичн. файл

   }


//Цикл вывода информации о студентах из обоих двоичных файлов

//Позиционирование указателей на начало каждого двоичного файла

rewind(fd1);

rewind(fd2);

printf("\nИнформация о студентах до сортировки\n");

fread(&so1,sizeof(so1),1,fd1);           //Чтение структуры из 1-го двоичн. файла

fread(&sx1,sizeof(sx1),1,fd2);           //Чтение структуры из 2-го двоичн. файла

while(!feof(fd1))

   {

    printf("\n%s %s %d ",so1.fam,so1.name,so1.kurs);

    for(i=0;i<3;i++)

       printf("%d ",so1.oc[i]);

   printf("%c %d",sx1.pol,sx1.god);

   fread(&so1,sizeof(so1),1,fd1);

   fread(&sx1,sizeof(sx1),1,fd2);

   }

//Сортировка информации в двоичных файлах методом "пузырька"

do

{

fl=0;                                    //Устанавливаем флаг в 0

//Позиционирование указателей на начало каждого двоичного файла

rewind(fd1);

rewind(fd2);

//Читаем по одной структуре из 1-го и 2-го двоичных файлов

fread(&so1,sizeof(so1),1,fd1);         

fread(&sx1,sizeof(sx1),1,fd2);

//Цикл однократного прохода по файлам

//Попарно сравниваем и, при необходимости, обмениваем местами структуры          

while(!feof(fd1))

{

 //Читаем еще по одной структуре из каждого файла

 fread(&so2,sizeof(so2),1,fd1);       

 if(feof(fd1)) break;

 fread(&sx2,sizeof(sx2),1,fd2);

 //Сравниваем фамилии 

 if(strcmp(so1.fam,so2.fam)>0)

   {

   //Обмен местами двух структур в 1-м файле

   ft=ftell(fd1)-2*sizeof(so1);

   fseek(fd1,ft,SEEK_SET);

   fwrite(&so2,sizeof(so2),1,fd1);

   fwrite(&so1,sizeof(so1),1,fd1);

   //Обмен местами двух структур в 1-м файле

   ft=ftell(fd2)-2*sizeof(sx1);

   fseek(fd2,ft,SEEK_SET);

   fwrite(&sx2,sizeof(sx2),1,fd2);

   fwrite(&sx1,sizeof(sx1),1,fd2);

   fl++;                                               //Увеличение флага в случае перестановки

   }

 //Возвращаем указатель на одну структуру назад в 1-м файле

 ft=ftell(fd1)-sizeof(so1);

 fseek(fd1,ft,SEEK_SET);

 

 //Чтение очередной структуры из 1-го файла

 fread(&so1,sizeof(so1),1,fd1);

 //Возвращаем указатель на одну структуру назад во 2-м файле

 ft=ftell(fd2)-sizeof(sx1);

 fseek(fd2,ft,SEEK_SET);

 

 //Чтение очередной структуры из 2-го файла

 fread(&sx1,sizeof(sx1),1,fd2);

 }

}while(fl>0);

//Цикл вывода информации о студентах из обоих двоичных файлов

//Выход на начало каждого файла

rewind(fd1);

rewind(fd2);

printf("\n\nИнформация о студентах после сортировки\n");

//Читаем по одной структуре из 1-го и 2-го двоичных файлов

fread(&so1,sizeof(so1),1,fd1);

fread(&sx1,sizeof(sx1),1,fd2);

while(!feof(fd1))

   {

    printf("\n%s %s %d ",so1.fam,so1.name,so1.kurs);

    for(i=0;i<3;i++)

       printf("%d ",so1.oc[i]);

   printf("%c %d",sx1.pol,sx1.god);

   fread(&so1,sizeof(so1),1,fd1);

   fread(&sx1,sizeof(sx1),1,fd2);

   }

//Подсчет среднего балла по математике для юношей и девушек

rewind(fd1);

rewind(fd2);

//Обнуляем кол-ва и суммы

kolm=0;

kolw=0;

srm=0;

srw=0;

fread(&so1,sizeof(so1),1,fd1);

fread(&sx1,sizeof(sx1),1,fd2);

while(!feof(fd1)&&!feof(fd2))

 {

  if(sx1.pol=='м')

    { kolm++;  

      srm+=so1.oc[1];

    }

  if(sx1.pol=='ж')

    { kolw++;  

      srw+=so1.oc[1];

    }

  fread(&so1,sizeof(so1),1,fd1);

  fread(&sx1,sizeof(sx1),1,fd2);

 }

if(kolm) srm/=kolm;

if(kolw) srw/=kolw;

if(srm>srw)

  printf("\n\nМатематику лучше сдали юноши");

else if(srm<srw)

      printf("\n\nМатематику лучше сдали девушки");

    else printf("\n\nУ девушек и юношей одинаковый результат по математике");

fcloseall();               //Закрытие всех файлов

getch();

}


 

А также другие работы, которые могут Вас заинтересовать

46986. Развитие детского психоанализа в работах А.Фрейд. Защитные механизмы личности. Понятие социализации 42 KB
  Анна Фрейд дочь Зигмунда Фрейда продолжила и развила классическую теорию и практику психоанализа. Фрейд указала истоки психоаналитического интереса к детям. Фрейдом особенностям детского развития: детской сексуальности Эдипова и кастрационного комплексов. Фрейд разделяет личность на ее устойчивые составные части: бессознательное или Оно Я СверхЯ .
46987. Subordinate clauses of secondary nominal positions 42 KB
  Attributive clauses function as modifiers to a word of nominal character, which is generally called the antecedent. Usually an attributive clause immediately follows its antecedent, although some types may occasionally be distant
46988. Язык художественной литературы 42 KB
  В качестве аргументов против выделения стиля художественной литературы приводятся следующие: 1 язык художественной литературы не включается в понятие литературного языка; 2 он многостилен незамкнут не имеет специфических примет которые были бы присущи языку художественной литературы в целом; 3 у языка художественной литературы особая эстетическая функция которая выражается в весьма специфическом использовании языковых средств. Язык художественной литературы и литературный язык понятия не тождественные. В языке художественной литературы...
46990. Статистика населения. Перестрахование как операция по достижению финансовой устойчивости страховщика 44.64 KB
  Статистика населения. Статистика населения это древнейшая отрасль статист науки которая изучает население и процессы связанные с его динамикой с колич кач стороной в конкр условиях общественного развития. Статистика населения использует свои методы с целью более полного изучения анализа и прогнозирования населения страны регионов и т. К основным демографическим показателям относятся: численность и состав населения число родившихся и умерших число браков и разводов численность прибывших и выбывших из страны.
46991. Инновации в профессиональном образовании. Психология профессионального обучения и социально-профессионального воспитания 42.5 KB
  Психология профессионального обучения и социальнопрофессионального воспитания Наиболее общим понятием является научение которое определяется как целесообразное изменение деятельности и поведения в процессе выполнения какихлибо действий: физических умственных.Происходит все более качественное выполнение действий при ослабевающем временами произвольном внимании устраняются лишние движения появляются возможности положительного переноса навыка. 4 Высокоавтоматизированный навык точное экономное устойчивое выполнение действий 5...