\section{Файлы} В предыдущих разделах мы познакомились почти со всеми существующими в языке С типами данных, как примитивными, так и ссылочными. Довольно подробно рассмотрели работу почти всех операторов языка. Пришло время выйти за пределы программы (хотя бы в части хранения данных) и поговорить о взаимодействии программы с операционной системой, а именно - о чтении и записи в файловую систему компьютера. Файловая система \textit{любого} компьютера - \textbf{это структура}. Для языка С файл - это тоже структура. Структура, хранящая данные о положении курсора в файле, его название, буферы, флажки и прочие свойства. Файлы делятся на два основных типа - текстовые и бинарные. Мы рассмотрим работу с текстовыми, поскольку работа с бинарными практически ничем не отличается, а текст всё-таки проще воспринимается. С места в карьер, опишем переменную, хранящую указатель на структуру <<файл>>. Вся основная работа будет проходить через неё. Для того, чтобы присвоить этой переменной указатель на какой-то реальный файл будем пользоваться функцией \code{fopen();}, которая возвращает указатель на адрес в памяти. Функция принимает в качестве аргументов имя файла в двойных кавычках и режим его открытия. \begin{lstlisting}[language=C,style=CCodeStyle] FILE *f; \end{lstlisting} Основных используемых режимов шесть: \begin{itemize} \item чтение, \item запись, \item добавление, \item двоичное чтение, \item двоичная запись, \item двоичное добавление. \end{itemize} \subsection{Запись} Функции \textbf{записи и добавления} \textit{создают} файл в случае его отсутствия. А функция \textbf{записи} \textit{стирает} файл, если он существует и не пустой. Итак создадим текстовый файл с каким-то неожиданным названием, вроде \code{filename.txt}, и скажем нашей программе, что нужно будет его создать, если его не существует, перезаписать, если существует, а дальше мы будем в него записывать данные, то есть режим открытия будет \code{"w"}. Имя файла в аргументе может быть как полным (абсолютным), вроде \code{C:\\FILE.TXT} тогда файл будет создан в корне диска C, или \code{/home/user/file.txt}. Также имя файла может быть и относительным, каким мы его указали сейчас, это значит, что файл будет создан в той папке, в которой запускается наша программа. \begin{lstlisting}[language=C,style=CCodeStyle] f = fopen("filename.txt", "w"); \end{lstlisting} В случае, если файл не найден или по какой-то причине не создался, в переменную \code{f} запишется нулевой указатель, поэтому перед тем, как начать работу с файлом, нужно проверить, смогла-ли программа его открыть, для этого запишем условие, что если в наш указатель записался нулевой указатель, то дальнейшее выполнение функции \code{int main (int argc, char *argv[])} не имеет смысла. \begin{lstlisting}[language=C,style=CCodeStyle] if (file == NULL) return 1; \end{lstlisting} Если всё хорошо, можем записывать в файл данные. Для записи в файл есть несколько функций, мы воспользуемся самой простой и очевидной:\code{fprintf();}, в неё в качестве первого аргумента обязательно нужно передать указатель на файл, в который мы собираемся писать, а дальше можно использовать как знакомый нам \code{printf();} со всеми его удобствами, заполнителями, экранированными последовательностями и дополнительными аргументами. После того как мы закончили запись в файл его необходимо закрыть, вызвав функцию \code{fclose();} \begin{lstlisting}[language=C,style=CCodeStyle] fprintf(f, "Hello, files! %s", "we did it!\n"); fclose(f); \end{lstlisting} Запустив проект, посмотрим что у нас получилось. В терминале не будет никакого вывода, но если перейти в проводник, то можно увидеть, что в папке проекта появился файл \code{filename.txt}, в котором написано наше содержимое. Открывается такой текстовый файл любым обычным блокнотом \subsection{Чтение} Отлично, программа теперь умеет сохранять результаты своей работы в файлы, то есть у нас появилось ещё одно средство вывода информации, помимо терминала. Теперь давайте рассмотрим не менее важную тему, а именно - чтение из файла. Ведь тогда мы сможем не просто иначе выводить информацию, но и сохранять её на жёстком диске от запуска к запуску программы, а значит хранить какие-то настройки или промежуточные значения. Для этого нам нужно совершить несколько несложных действий с применением неожиданно знакомой функции \code{fscanf();} чтобы прочитать форматированные значения из файла: \begin{itemize} \item создать массив \code{char[]}, для примера, назовем его \code{word}; \item нужный файл открыть в режиме чтения; \item при помощи функции \code{fscanf();} считать из файла некоторую строку, которую положим в этот массив. \end{itemize} Далее выведем в консоль строку которую прочитали, для этого воспользуемся привычной нам функцией \code{printf();} а затем выведем пустую строку. Запустим нашу программу и увидим, что в консоль вывелось слово \code{Hello}, функция \code{fscanf();} отлично отработала, прочитав все символы из файла до пробела. \begin{lstlisting}[language=C,style=CCodeStyle] char word[256]; f = fopen("filename.txt", "r"); fscanf(f, "%s", &word); printf("%s\n", word); \end{lstlisting} Но сколько данных читать? Как узнать, что достигнут конец файла? Для этого придумали функцию \code{feof();} (англ. file: end of file) возвращающую ноль, если конец файла не достигнут, и единицу если достигнут. Опишем цикл, который выведет в консоль все полученные \code{fscanf();} строки из нашего файла. То есть, мы циклически пройдемся по всему файлу, пока не будет достигнут его конец и будем выводить считанные строки в консоль: \begin{lstlisting}[language=C,style=CCodeStyle] char word[256]; f = fopen("filename.txt", "r"); while (!feof(file)) { fscanf(f, "%s", &word); printf("%s ", word); } printf("\n"); fclose(f); \end{lstlisting}