Примеры работы с файлами на С, С++ [АйТи бубен]

Функции библиотеки stdio.h

fopen

Функция открывает файл.

filename — путь к файлу

mode — тип доступа

Все вышеописанные режимы предназначены для текстового открытия файла. Для двоичного открытия перед режимом достаточно добавить букву b. Например, br.

Если функция отработала успешно, из неё возвращается указатель на открытый файл, в противном случае — нуль.

Указатель на открытый файл принято хранить в типе данных FILE*.

fclose

int fclose( FILE *stream )

Функция закрывает файл.

stream — указатель на закрываемый файл.

Если всё проходит успешно, то данная функция возвращает 0, или EOF в случае ошибки.

EOF (End Of File) — обозначение конца файла.

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

Считывает строку начиная с текущей позиции.

Считывание останавливается:

…если был найден символ перехода на новую строчку ( он помещается в строку ) …если достигнут конец файла …если считано n-1 символов. string — cтрока, в которую попадают считанные данные

n — количество элементов в string

stream — указатель на открытый файл

Если всё прошло успешно функция возвращает считанную строку, если произошла ошибка или достигнут конец файла возвращается 0.

int fputs( const char *string, FILE *stream )

Записывает строку в файл, начиная с текущей позиции.

string — строка для записи

stream — указатель на открытый файл, куда производиться запись

Если функция отрабатывает успешно из неё возвращается неотрицательное значение. При ошибке возвращается EOF.

size_t fread( void *buffer, size_t size, size_t count, FILE *stream )

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

buffer — адрес массива, куда запишутся данные

size — размер элемента массива в байтах

count — максимальное количество элементов для считывания

stream — указатель на открытый файл.

Функция возвращает количество считанных байт.

Примечание: Тип данных size_t определен в библиотеке stdio.h следующим образом: typedef unsigned int size_t;. Другими словами, это обычный беззнаковый int.

size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream )

Функция записывает массив данных в файл.

buffer — адрес массива, где содержатся данные

size — размер элемента массива в байтах

count — максимальное количество элементов для записи в файл

stream — указатель на открытый файл.

Функция возвращает количество записанных байт.

int feof( FILE *stream )

Функция проверяет достигнут ли конец файла.

stream — указатель на открытый файл

Функция возвращает ненулевое значение, если достигнут конец файла, нуль возвращается в противном случае.

int _fileno( FILE *stream )

Данная функция возвращает дескриптор файла.

stream — указатель на открытый файл.

int fseek ( FILE *stream, int offset [, int whence] )

Устанавливает смещение в файле

stream — указатель на открытый файл

offset — смещение, измеряемое в байтах от начала файла

whence — точка, от которой производится смещение

SEEK_SET (0) — начало файла SEEK_CUR (1) — позиция текущего указателя файла SEEK_END (2) — конец файла (EOF) Функция возвращает значение 0, если указатель файла успешно перемещен, и ненулевое значение в случае неудачного завершения.

Видео

Оператор fscanf()

Для считывания слова из файла в си используется команда fscanf(). Эта команда аналогична  команде ввода информации с клавиватуры в си scanf() только первый параметр это указатель на файл fscanf(указатель на файл,"%формат ввода данных1% форматввода данных2…",&перменная1,&переменная2…); Например команда  fscanf(fin,"%d%d%d",&a,&b,&c); считает из файла, который привязан к указателю на файл fin строку из трех целочисленных переменных Разберем пример программы, которая считывает из текстового файла data.txt в которые записаны три столбца цифр информацию и записывает ее в массивы. Для каждого столбца информации свой массив. Подробно о работе  с массивами в Си. #include <stdio.h> #include <conio.h> main() {     int a[10];       int b[10];       int c[10];       int i;   // определяем указатель на файл      FILE *fin; // открываем файл на чтение       fin = fopen("C:\\Users\\user\\Desktop\\data.txt", "r"); // построчное считывание из файла      for (i=0;i<3;i++)      { // считывание строки из  трех значений файла и запись в массивы          fscanf(fin,"%d%d%d",&a[i],&b[i],&c[i]);              } // вывод массивов на экран  for (i=0;i<3;i++)      {          printf("%d %d %d\n",a[i],b[i],c[i]);                 }         getch(); // закрытие файла      fclose(fin); }

Позиционирование указателя при записи файла

Режим «r» или «w» устанавливает каретку записи в начало файла. Режим «a» устанавливает каретку в конец имеющихся данных. Таким образом первый вариант перезаписывает файл, второй дописывает. При записи или чтении каретка передвигается на позицию, равную числу прочитанных или записанных байтов, или символов.

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

У данной функции следующий синтаксис: fseek(файл, количество байтов для смещения, начальная позиции);

Пояснение к функции:

  1. Параметр «файл» является переменной типа FILE, указывающая на директорию его расположения.
  2. Параметр «количество байтов для смещения» обладает типом long и в числовом формате указывает на сколько символов нужно переместить каретку.
  3. Параметр «начальная позиция» имеет числовой тип и указывает на каком по порядку от начала байте нужно установить каретку файла.
  4. В третий параметр можно вписать одну из встроенных в структуру FILE констант: SEEK_SET — устанавливает позицию на начало файла; SEEK_CUR — сохраняет текущую позицию в файле, если она была смещена; SEEK_END — устанавливает каретку на конечную позицию.

Пример использования функции fseek():

int main(void){ int i; \\ Переменная для сохранения символов в цикле char * str = «Hello»; \\ Первая строка записываемая в файл char * final_str; \\ Строка для дописывания в файл File * f = fopen(«text.txt», w); fputs(str, f); \\ Записываем первую строку в файл

fseek(f, 6, SEEK_SET); \\ Устанавливаем каретку на 6-ю позицию fputs(«World!», f); \\ С шестой позиции записываем в файл строку «World!» fseek(f, 0, SEEK_SET); \\ Устанавливаем позицию каретки в начало

while ((i = getc(f))!=EOF) \\ Получаем каждый символ файла и сохраняем его в переменную «final_str» { *final_str +=(char *)i; }

printf(«Содержание файла:», final_str); \\ Выводим содержимое файла на консоль fclose(f); }

Вывести атрибуты файла, директории

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

Ошибка открытия файла

Если вызов функции fopen прошёл неудачно, то она возвратит NULL. Ошибки во время работы с файлами встречаются достаточно часто, поэтому каждый раз, когда мы окрываем файл, необходимо проверять результат работы

Проблему вызывает случай, когда открывается сразу несколько файлов: если один из них нельзя открыть, то остальные также должны быть закрыты

В простых случаях можно действовать влоб, как в предыдущем куске кода. В более сложных случаях используются методы, подменяющиее RAII из С++: обёртки, или особенности компилятора (cleanup в GCC) и т.п.

Файловый ввод

Теперь мы попытаемся прочитать содержимое файла, который создали в предыдущем примере. Обратите внимание, ifstream возвратит , если мы достигли конца файла (это удобно для определения «длины» содержимого файла). Например:

12345678910111213141516171819202122232425262728293031323334 #include <iostream> #include <fstream> #include <string> #include <cstdlib> // для использования функции exit() int main ( ) { using namespace std ; // ifstream используется для чтения содержимого файла. // Попытаемся прочитать содержимое файла SomeText.txt ifstream inf ( «SomeText.txt» ) ; // Если мы не можем открыть этот файл для чтения его содержимого, if ( ! inf ) { // то выводим следующее сообщение об ошибке и выполняем функцию exit() cerr << «Uh oh, SomeText.txt could not be opened for reading!» << endl ; exit ( 1 ) ; } // Пока есть данные, которые мы можем прочитать, while ( inf ) { // то перемещаем эти данные в строку, которую затем выводим на экран string strInput ; inf >> strInput ; cout << strInput << endl ; } return ; // Когда inf выйдет из области видимости, то деструктор класса ifstream автоматически закроет наш файл }

Результат выполнения программы:

See
line
#1!
See
line
#2!

Хм, это не совсем то, что мы хотели. Как мы уже узнали на предыдущих уроках, оператор извлечения работает с «отформатированными данными», т.е. он игнорирует все пробелы, символы табуляции и символ новой строки. Чтобы прочитать всё содержимое как есть, без его разбивки на части (как в примере, приведенном выше), нам нужно использовать метод getline():

12345678910111213141516171819202122232425262728293031323334 #include <iostream> #include <fstream> #include <string> #include <cstdlib> // для использования функции exit() int main ( ) { using namespace std ; // ifstream используется для чтения содержимого файлов. // Мы попытаемся прочитать содержимое файла SomeText.txt ifstream inf ( «SomeText.txt» ) ; // Если мы не можем открыть файл для чтения его содержимого, if ( ! inf ) { // то выводим следующее сообщение об ошибке и выполняем функцию exit() cerr << «Uh oh, SomeText.txt could not be opened for reading!» << endl ; exit ( 1 ) ; } // Пока есть, что читать, while ( inf ) { // то перемещаем то, что можем прочитать, в строку, а затем выводим эту строку на экран string strInput ; getline ( inf , strInput ) ; cout << strInput << endl ; } return ; // Когда inf выйдет из области видимости, то деструктор класса ifstream автоматически закроет наш файл }

Результат выполнения программы:

See line #1!
See line #2!

Отличие работы с потоками в Си от других языков

Как видно, язык Си не использует обращение к объектам для оперирования с файлами. Для открытия потока здесь даже не применяется конструкция new IOstream(). Ведь Cи является процедурным языком и в нем не используется парадигма ООП. Тем не менее, если открывать поток без сохранения в переменную, то дальнейшее применение функций должно сопровождаться записью в их параметры директории к файлу, какая была указана при открытии.

Ранее мы создавали переменную “f” для сохранения потока. Без нее всегда придется писать строку на подобие “C\:files\index.txt”. Данный подход достаточно неудобный и требует постоянной записи строки. При этом, все равно придется закрывать поток. Проще сохранить его в переменную – это дает гарантию тог, что работа всегда осуществляется с данным потоком.

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

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

При открытии файла для двоичного доступа, вторым параметром функции fopen() является строка «rb» или «wb».

Тема о работе с двоичными файлами достаточно сложная, для ее изучения требуется отдельный урок. Здесь будут отмечены только особенности функций чтения-записи в файл, который рассматривается как поток байтов.

Функции fread() и fwrite() принимают в качестве параметров:

  1. адрес области памяти, куда данные записываются или откуда считываются,
  2. размер одного данного какого-либо типа,
  3. количество считываемых данных указанного размера,
  4. файловый указатель.

Эти функции возвращают количество успешно прочитанных или записанных данных. Т.е. можно «заказать» считывание 50 элементов данных, а получить только 10. Ошибки при этом не возникнет.

Пример использования функций fread() и fwrite():

Здесь осуществляется попытка чтения из первого файла 50-ти символов. В n сохраняется количество реально считанных символов. Значение n может быть равно 50 или меньше. Данные помещаются в строку. То же самое происходит со вторым файлом. Далее первая строка присоединяется ко второй, и данные сбрасываются в третий файл.

  1. Напишите программу, которая запрашивает у пользователя имя (адрес) текстового файла, далее открывает его и считает в нем количество символов и строк.
  2. Напишите программу, которая записывает в файл данные, полученные из другого файла и так или иначе измененные перед записью. Каждая строка данных, полученная из файла, должна помещаться в структуру.

Курс с решением части задач:android-приложение, pdf-версия

Теги