Все до сих пор написанные программы читали из стандартного ввода и писали в стандартный вывод. Что же делать, если требуется что-то считать из файла или записать в какой-либо файл.
Прежде чем можно считывать из некоторого файла или записывать в него, этот файл должен быть открыт с помощью функции fopen из стандартной библиотеки. Функция fopen берет внешнее имя (например test.cpp), проводит некоторые обслуживающие действия и переговоры с операционной системой (детали которых не должны нас касаться) и возвращает внутреннее имя, которое должно использоваться при последующих чтениях из файла или записях в него.
Это внутреннее имя, называемое "указателем файла", фактически является указателем структуры, которая содержит информацию о файле, такую как место размещения буфера, текущая позиция символа в буфере, происходит ли чтение из файла или запись в него и тому подобное. Пользователи не обязаны знать эти детали, потому что среди определений для стандартного ввода-вывода, получаемых из файла stdio.h, содержится определение структуры с именем FILE(большими буквами). Единственное необходимое для указателя файла описание демонстрируется примером:
FILE *fopen(), *fp;
Здесь говорится, что fp является указателем на FILE и fopen возвращает указатель на FILE. Обратите внимание, что FILE является именем типа, подобным int, а не ярлыку структуры; это реализовано как typedef.
Фактическое обращение к функции fopen в программе имеет вид:
fp=fopen(NAME,MODE);
Первым аргументом функции fopen является "имя" файла, которое задается в виде символьной строки. Второй аргумент MODE ("режим") также является символьной строкой, которая указывает, как этот файл будет использоваться. Допустимыми режимами являются: чтение ("r"), запись ("w") и добавление ("a").
Если вы откроете файл, который еще не существует, для записи или добавления, то такой файл будет создан. Открытие существующего файла на запись приводит к отбрасыванию его старого содержимого. Попытка чтения несуществующего файла является ошибкой. Ошибки могут быть обусловлены и другими причинами (например, попыткой чтения из файла, не имея на то разрешения). При наличии какой-либо ошибки функция возвращает нулевое значение указателя NULL (константа определенная с помощью define файле stdio.h).
Другой необходимой вещью является способ чтения или записи, если файл уже открыт. Здесь имеется несколько возможностей, из которых getc и putc являются простейшими. Функция getc возвращает следующий символ из файла; ей необходим указатель файла, чтобы знать, из какого файла читать. Таким образом,
c=getc(fp)
помещает в "c" следующий символ из файла, указанного посредством fp, и EOF(endoffile константа определенная с помощью define равная -1 в stdio.h) если достигнут конец файла.
Функция PUTC, являющаяся обращением к функции getc,
putc(c,fp)
помещает символ "c" в файл fp и возвращает "c".
При запуске программы автоматически открываются три файла, которые снабжены определенными указателями файлов. Этими файлами являются стандартный ввод, стандартный вывод и стандартный вывод ошибок; соответствующие указатели файлов называются stdin, stdout и stderr. Обычно все эти указатели связаны с терминалом, но stdin и stdout могут быть перенаправлены на файлы или в поток (pipe).
Функция fclose является обратной по отношению к fopen; она разрывает связь между указателем файла и внешним именем, установленную функцией fopen, и высвобождает указатель файла для другого файла. Большинство операционных систем имеют некоторые ограничения на число одновременно открытых файлов, которыми может распоряжаться программа, поэтому следует разрывать связь между указателями и уже отработанными файлами.
Пример 1.
Даны 3 файла. Записать в третий файл содержимого первого, а потом с новой строки содержимое второго файла.
#include <stdio.h>
void main (void)
{ char c;
FILE *fp1,*fp2, *fp3;
fp1=fopen(“file1.txt”,"r");
fp2=fopen(“file2.txt”,"r");
fp3=fopen(“file3.txt,"w");
if (fp1==0||fp2==NULL||fp3==NULL)
{printf ("error\n");
fclose(fp1);
fclose(fp2);
fclose(fp3);
return; /*если произошла ошибка то нам не нужно дальше продолжать
} работу*/
while((c=getc(fp1))!=EOF)
putc(c,fp3);
putc('\n',fp3);
while((c=getc(fp2))!=EOF)
putc(c,fp3);
fclose(fp1);
fclose(fp2);
fclose(fp3);
}
Пример2
Даны 3 файла. Записать в третий файл содержимого первого и второго файла, так что сначала записывается символ из первого файла потом символ из второго файла и т.д. если один файл длиннее другого то по окончании короткого файла записываем в третий файл все оставшиеся символы более длинного файла
Будем решать задачу следующим образом пока какой либо файл не кончится будем записывать по очереди символы из файлов как только какой-нибудь файл кончится проверим какой кончился и запишем все оставшиеся символы не кончившегося файла.
#include <stdio.h>
void main (void)
{ char c,p;
FILE *fp1,*fp2, *fp3;
fp1=fopen(“file1.txt”,"r");
fp2=fopen(“file2.txt”,"r");
fp3=fopen(“file3.txt,"w");
if (fp1==0||fp2==NULL||fp3==NULL)
{printf ("error\n");
fclose(fp1);
fclose(fp2);
fclose(fp3);
return; /*если произошла ошибка то нам не нужно дальше продолжать
} работу*/
while ((c=getc(fp1))!=-1&&(p=getc(fp2))!=EOF)
{putc(c,fp3);
putc(p,fp3);
}
if(c==EOF)
/*так как в си работает аппарат так называемых «ленивых вычислений», то когда в предыдущем цикле с станет равно EOF выражение после операции && вычислятся не будет и в p не появится нового символа из второго файла, значит нам надо опять считать очередной символ и записать его в третий файл*/
while((p=getc(fp2))!=EOF)
putc(p,fp3);
else
/*так как в первом цикле мы сначала считываем символ из первого файла а затем из второго то когда закончится второй файл в с у нас будет символ первого, который мы не записали еще в третий поэтому надо сначала записать его в третий файл, а потом считывать все остальные*/
{ putc(c,fp3);
while((c=getc(fp1))!=EOF)
putc(c,fp3);
}
fclose(fp1);
fclose(fp2);
fclose(fp3);
}