Файлы (С )
Ввод – вывод элементов массива
Ввод – вывод элементов массива
Ввод – вывод элементов массива
Ввод – вывод элементов массива
Ввод – вывод элементов массива
737.50K
Category: programmingprogramming

Программирование на С++. Файлы

1.

Программирование на С++
Тема 10. Файлы

2.

Файлы
Виды файлов в С(С++):
Текстовые ;
Двоичные (binary).
Основные действия, производимые над файлами:
открытие,
обработка,
закрытие.

3.

Файлы
Чаще всего под файлом понимают именованную совокупность данных на внешнем носителе
информации.
В данной теме мы рассмотрим работу с дисковыми файлами.
Поток позволяет ассоциировать файл с буфером, который позволяет осуществить эффективный
ввод - вывод. Буфер – это выделенный участок памяти. При буферном вводе информация с
носителя информации (из файла) вначале поступает в буфер, а затем оттуда передается
прикладной программе. Аналогично и при буферном выводе – информация из программы
вначале поступает в буфер, а затем – на носитель информации (в файл).
Если для ввода и вывода в программе используются потоки, то для программиста буферизация
выполняется автоматически.
В С (С++) различают два вида файлов : текстовые и двоичные (бинарные).
Текстовые файлы состоят из строк символов и предназначены для чтения человеком. На диске
текстовые файлы хранятся в виде сплошной последовательности символов, и их деление на
строки становится заметным лишь в момент вывода на экран или на печать, так как именно при
выводе управляющие символы (например, \n) начинают выполнять свои функции.
Бинарный файл – это последовательность байтов, однозначно соответствующая
последовательности байтов, записанной на внешнем устройстве.
Основными действиями, производимыми над файлами, являются их открытие, обработка и
закрытие.

4.

Файлы (С)

5.

Файлы (С )
Основные функции для работы с файлами (stdio.h) :
Функция
Описание
fopen()
Открывает файл
fclose()
Закрывает файл
fputc()
Записывает символ в файл
fgetc()
Считывает символ из файла
fgets()
Считывает строку из файла
fputs()
Записывает строку в файл
fseek()
Устанавливает курсор на заданный байт файла
ftell()
Возвращает текущую позицию курсора
fprintf()
Файловый аналог функции printf()
fscanf()
Файловый аналог функции scanf()
feof()
ferror()
rewind()
Возвращает истинное значение, если достигнут конец файла
Возвращает истинное значение, если произошла ошибка
Устанавливает курсор в начало файла
remove()
Стирает файл
fflush()
Очищает поток

6.

Файлы (С )
Синтаксис объявления указателя на поток:
#include <stdio.h>
FILE * имя указателя;
Прототип функции fopen():
FILE * fopen(const char *имя_файла, const char
*режим_доступа)
Режимы доступа к файлам:
Режим
Описание
r
Открыть файл для чтения, модификации файла запрещены
w
Создать новый файл только для записи. При попытке открыть таким
способом существующий файл происходит перезапись файла. Чтение
данных из файла запрещено.
a
Открыть файл для дозаписи. Если файла с указанным именем не
существует, он будет создан.
r+
Открыть существующий файл для чтения и записи
w+
Создать новый файл для чтения и записи
a+
Открыть существующий файл для дозаписи и чтения

7.

Файлы (С )
Для управления потоками используются указатели.
В языке С указатель на поток является указателем на тип с именем FILE.
Тип FILE определяется в заголовочном файле stdio.h и представляет собой структуру,
описывающую параметры реализации потока, такие, например, как адрес буфера, с которым
будет работать файл, адрес текущего символа, который будет передаваться (приниматься) в
прикладную программу, и т. д..
При открытии файлов порция информации из дискового файла поступает в буфер и указатель на
поток получает адрес буфера.
В языке С файлы открываю с помощью функции fopen(). Функция fopen() имеет два параметра.
Первый параметра является строковой константой, которая задает имя файла и путь к нему.
Второй параметр – тоже строковая константа – задает режим доступа к файлу. Режим доступа
описывает две составляющие: способ доступа (чтение или запись) и тип файла (текстовый или
двоичный).
Для работы с текстовым файлом можно к режиму доступа добавить строчную латинскую букву t,
но делать это не обязательно, так как файлы открываются в текстовом виде по умолчанию.
Для работы с бинарными файлами обязательно нужно к режиму доступа добавить строчную
латинскую букву b.

8.

Файлы (С )
Варианты открытия файла:
Вариант 1: #include <stdio.h>
FILE *f;
f = fopen("D:\\text.txt", "r");
{ // обработка файла
}
Вариант 2:
#include <stdio.h>
FILE *f;
if((f = fopen("D:\\text.txt", "r"))!=NULL)
{ // обработка файла
}
Прототип функции fclose():
int fclose(FILE * f)

9.

Файлы (С )
Таким образом, чтобы открыть файл (например, текстовый файл) для чтения, нужно произвести
следующие действия :
Объявить указатель на поток;
Открыть файл функцией fopen() (т.е. связать указатель на поток с дисковым файлом и
указать режим доступа r).
При попытке открыть существующий файл можно допустить ошибку в его имени или в указании
пути к нужному файлу. Это вызывает ошибку выполнения программы. Следует предвидеть
подобные ситуации и проводить проверку возможности открытия файла. Такую проверку
осуществить довольно легко, так как функция fopen() возвращает значение указателя на поток в
случае его успешного открытия и значение NULL (нулевой указатель), если доступ к файлу
невозможен .
Файлы, открываемые в режиме записи, также нуждаются в аналогичной проверке.
Функция fclose() закрывает поток, открытый ранее функцией fopen(). Она записывает все
оставшиеся в буфере данные в файл и закрывает его, используя команды операционной
системы. Ошибка, возникшая при закрытии файла, может породить множество проблем, начиная
с потери данных и разрушения файлов и заканчивая непредсказуемыми последствиями для
программы. Кроме того, функция fclose() освобождает управляющий блок файла, связанного с
потоком, позволяя использовать этот блок повторно.
Операционная система ограничивает количество одновременно открытых файлов, поэтому,
прежде чем открыть один файл, следует закрыть другой.
Параметр f представляет собой указатель файла, возвращенный функцией fopen(). Если функция
вернула нулевой указатель, значит, файл закрыт успешно. Как правило, функция fclose()
выполняется неверно, если диск был преждевременно вынут из дисковода или переполнен.

10.

Файлы (С )
Функции ввода - вывода для обработки текстовых файлов:
int fscanf (FILE *stream, форматная строка, список
аргументов);
int fprintf (FILE *stream, форматная строка, список
аргументов);
int fgetс(FILE *stream)
int fputс(char с, FILE *stream)
char *fgets(char *s, int size, FILE *stream)
int fputs(char *s, FILE *stream)

11.

Файлы (С )
Рассмотрим основные варианты обработки текстовых файлов.
При работе с текстовыми файлами возможна их посимвольная или построчная обработка.
Функции fprintf() и fscanf() , fgetc() и fputc() используют для посимвольной обработки, а функции
fgets() и fputs() для построчной обработки текстовых файлов.
Функции ввода-вывода fprintf() и fscanf() работают аналогчно функциям printf() и scanf(), но имеют
дополнительный аргумент, являющийся указателем на файловый поток.
Функция fgetc () считывает символ из файла, открытого функцией fopen() в режиме чтения.
Параметр stream является указателем на поток, возвращенным функцией fopen(). Функция fgetc()
возвращает целочисленную переменную, младший байт которой содержит введенный символ.
Если возникла ошибка, старший байт этой переменной равен нулю. Если при чтении
обнаруживается конец файла, функция fgetc() возвращает константу EOF.
Функция fputc() записывает символ в файл, открытый с помощью функции fopen(). Параметр
stream представляет собой указатель файла, возвращенный функцией fopen(), а аргумент
является символом, подлежащим выводу. Указатель stream сообщает функции putc(), в какой
именно файл следует произвести запись. Несмотря на то, что параметр имеет тип int, в файл
записывается лишь младший байт. Если функция fputc() выполнена успешно, она возвращает
символ, записанный ею в файл. В противном случае она возвращает константу EOF.
Функция fgets() считывает строку из size символов из потока stream, связанного с текстовым
файлом, в строковую переменную s;
Функция fputs() записывает строку s в поток stream, связанный с текстовым файлом;

12. Файлы (С )

Пример 1. Чтение элементов одномерного массива из текстового файла и
запить в текстовый файл:
#include <iostream>
#include <stdio.h>
using namespace std;
int main(void)
{ int n = 0; int a[10];
FILE *f; // объявление потока
f = fopen("D:\\abc1.txt","r");
if (f) { cout << "Read file ! \n";
while(!feof(f))
{ fscanf(f,"%3d",&a[n]); // чтение из файла
n++;
} fclose(f);
for(int i=0;i < n;i++)
cout << a[i] << " ";
}
else cout << "File not found \n";

13. Ввод – вывод элементов массива

f = fopen("D:\\abc2.txt","w");
if (f) { for(int i = 0;i < n;i++)
fprintf(f,"%3d",a[i]); // запись в файл
cout << "\nFile write!";
fclose(f);
}
else cout << "File not found \n";
}

14.

Файлы (С )
Пример 2. Запись из исходного файла в выходной каждого третьего
символа.
#include <stdio.h>
int main(void)
{ FILE * f_in, * f_out;
int k = 1;
int ch;
if ((f_in = fopen("D:\\text.txt","r"))!= NULL)
{ printf("Read and write file!\n");
f_out = fopen("D:\\text2.txt","w");
while((ch = fgetc(f_in))!= EOF)
if ((k++ % 3) == 0)
fputc(ch, f_out);
fclose(f_in); fclose(f_out);
}
else printf("Error open file!\n");
}

15.

Строки и текстовые файлы
Пример 3:
//определить сколько чисел содержится в каждой строке тексто //вого файла. Длина каждой строки не превышает 100 символов
#include <stdio.h>
#include <iostream>
#include <ctype.h>
using namespace std;
int num(const char *str);
int main(void)
{ FILE * f; const int len = 101; int i = 1; char str[len];
f=fopen("D:\\FileTXT\\text3.txt","r");
if (f != NULL)
{ cout << "\nСколько чисел в каждой строке файла?";
while(!feof(f))
{ fgets(str,sizeof(str), f);
cout << "\nВ строке " << i << " - " << num(str);
i++;
} cout << endl;
} else cout << "Файл не найден!\n";
}
15

16.

Строки и текстовые файлы
int num(const char *str)
{ int count = 0;
while (*str)
{if (isdigit(*str) && !isdigit(*(str + 1))
&& *(str + 1) !='.')
count ++;
str++;
}
return count;
}
16

17.

Файлы (С )
Открытие бинарного файла для чтения и записи:
#include <stdio.h>
FILE *f;
if((f = fopen("D:\\bin_file.dat", "r+b"))!= NULL)
{ // обработка файла
}
Открытие для записи (создание) бинарного файла:
#include <stdio.h>
FILE *f;
if((f = fopen("D:\\bin_file.dat", "wb"))!= NULL)
{ // обработка файла
}
Функции ввода - вывода для обработки бинарных файлов:
size_t fread(const void *ptr, size_t site, size_t n, FILE
*stream)
size_t fwrite(const void *ptr, size_t site, size_t n, FILE
*stream)

18.

Файлы (С )
Способ хранения данных в бинарных (двоичных) файлах имеет два важных преимущества:
Увеличивается скорость извлечения из файла данных, не носящих чисто текстового характера,
так как не требуется действий по преобразованию их из текстового формата в двоичный.
Имеет место экономия памяти и дискового пространства, поскольку двоичная кодировка более
компактна и нет необходимости в использовании управляющих символов.
Принципиально обработка двоичных файлов не очень сильно отличается от обработки текстовых
файлов. В любом случае, прежде чем работать с файлом, следует открыть файл, указав режим
доступа. Открыть файл для двоичной обработки можно посредством вызова функции fopen(), но ко
всем режимам доступа добавляют строчную латинскую букву b. Режимы доступа одинаковы для
текстовых и двоичных файлов. Если после вызова функции fopen() указатель на файловый поток f
не равен нулю, его можно использовать в последующих обращениях к функциям работы с
двоичными файлами, таким, как fwrite() и fread() . Закрывают двоичные файлы, как и текстовые,
функцией fclose().
Функции fwrite() и fread() так же могут быть использованы для работы с текстовыми файлами, хотя
чаще их используют для работы с бинарными файлами. Параметры функций:
ptr – указатель на исходные данные, читаемые из файла (записываемые в файл);
size – размер в байтах одного элемента данных;
Замечание. size_t – специальный идентификатор типа, который введен для обозначения типа
результата, вычисляемого операцией sizeof. На самом деле идентификатор size_t является
синонимом unsigned int.
n – число записываемых в файл элементов данных; stream – указатель на файловый поток.
Существует два способа доступа к элементам двоичных файлов: последовательный и
произвольный.
Последовательный доступ к элементам файла особенно эффективен, если нужно перебрать все
данные, хранящиеся в нем. Кроме того, если файл открыт для записи, но еще не содержит данных
(т. е. пустой), то заполнение его возможно лишь в последовательном режиме.

19. Ввод – вывод элементов массива

Запить элементов одномерного массива в бинарный файл и
чтение из бинарного файла:
#include <iostream>
#include <stdio.h>
using namespace std;
int main(void)
{ int n; int *a,*b;
FILE *f; // объявление потока
cout << "\n n = "; cin >> n; cout << "\n";
a = new int [n];
for (int i = 0; i < n; i++)
{ cout << "a[" << i << "]:"; cin >> a[i];
} cout << "\n";
f = fopen("D:\\abc3.dat","wb");
fwrite(&n,sizeof(int),1,f);
fwrite(a,sizeof(int),n, f);
fclose(f);

20. Ввод – вывод элементов массива

f = fopen("D:\\abc3.dat", "rb");
if (f)
{ fread(&n,sizeof(int),1, f);
b = new int [n];
fread(b, sizeof(int), n, f);
for (int i = 0; i < n; i++)
cout << b[i] << " ";
}
fclose(f);
}

21.

Файлы (С )
Произвольный доступ к элементам двоичных файлов
Прототип функции fseek():
int fseek (FILE *stream, long offset, int whence);
Значения аргумента whence :
Значение
Описание
SEEK_SET
Перемещение файлового указателя происходит относительно
начала файла
SEEK_END
Перемещение файлового указателя происходит относительно
конца файла
SEEK_CUR
Перемещение файлового указателя происходит относительно
текущей позиции файлового указателя

22.

Файлы (С )
Организация произвольного доступа к компонентам файла позволяет считывать значения из
любой позиции в файле, а также записывать новую информацию в любое место в файле. Но к
файлам с произвольным доступом предъявляется одно жесткое требование: их компоненты
должны иметь одинаковую длину. Двоичные файлы позволяют обеспечить удовлетворение этого
требования. О том, чтобы данные, которые будут находиться в файле произвольного доступа,
имели одинаковый размер, следует позаботиться в момент создания файла.
Вспомним о том, что первичная запись в файл возможна только в режиме последовательного
доступа.
Для организации произвольного доступа к элементам файла используют функцию fseek(),
прототип которой описан в заголовочном файле stdio.h.
Функция fseek() перемещает внутренний указатель файлового потока, изменяя таким образом
место в файле, с которого начинается следующая операция чтения или записи. В случае
успешного завершения функция возвращает 0, в случае ошибки – ненулевое значение.
Параметры функции:
FILE *stream – указатель на открытый файловый поток;
long offset – число байтов, на которое нужно переместить файловый указатель в
направлении, указанном параметром whence. Для перемещения файлового указателя в
обратном направлении (в сторону начала файла) следует устанавливать offset равным
отрицательному значению;
int whence – указывает положение точки отсчета файлового указателя, от которой будет
происходить его перемещение Значения аргумента whence представлены в таблице.
При использовании функции fseek() следует соблюдать осторожность, так как попадание за
пределы файла чаще всего не приводит к генерации ошибки, поэтому программисту самому
следует принимать меры для предотвращения обращения к диску за пределами известных границ
файла.

23.

Файлы (С )
Произвольный доступ к элементам двоичных файлов
Прототип функции ftell():
long ftell (FILE *stream);
Операторы, демотстрирующие возможности функции fseek() :
fseek (f, sizeof(t), SEEK_CUR); // с текущей позиции на
// следующую
fseek (f, -sizeof(t), SEEK_CUR);
fseek (f, 0, SEEK_END);
// на предыдущую
// позицию
//на конец файла

24.

Файлы (С )
При организации произвольного доступа используется функция ftell(), осуществляющая
навигацию внутри файла. Прототип функции описан в stdio.h. Данная функция возвращает
внутренний указатель файлового потока, равный смещению в байтах от начала двоичного файла
до байта, с которого начинается следующая операция ввода – вывода. Это значение можно
передать функции fseek() .
Единственным параметром функции ftell() является указатель на открытый файловый поток.
Далее рассмотрим пример в котором организуется произвольный доступ к элементам двоичного
файла.

25.

Файлы (С )
Произвольный доступ к элементам двоичных файлов
Пример. Создать бинарный файл. В этом файле записать 0 на место
первого максимального элемента.
#include <stdio.h>
#include <iostream>
using namespace std;
void create(void);//прототип функции создания бинарного файла
void view(void);//прототип функции просмотра бинарного файла
void work(void);//прототип функции обработки бинарного файла
int main(void)
{ create(); // вызов функции создания
view(); // вызов функции просмотра
work(); // вызов функции обработки
view(); // вызов функции просмотра
}
бинарного
бинарного
бинарного
бинарного
файла
файла
файла
файла

26.

Файлы (С )
// определение функции создания бинарного файла
void create(void)
{ FILE * f; int number, n;
if ((f = fopen("D:\\file.dat","wb"))!= NULL)
{ cout << " Enter quantity numbers n = ";
cin >> n;
cout << " \nEnter numbers : ";
for (int i = 0; i < n; i++)
{ cin >> number;
fwrite(&number,sizeof(int),1,f);
}
fclose(f);
}
else
printf("Error create file!\n");
}

27.

Файлы (С )
// определение функции просмотра бинарного файла
void view(void)
{ int number;
FILE * f;
if ((f = fopen("D:\\file.dat","rb"))!= NULL)
{ cout << "\nNumbers: ";
while (fread(&number,sizeof(int),1,f))
cout << number << " ";
cout << "\n";
fclose(f);
}
else
}
printf("Error open file!\n");

28.

Файлы (С )
// определение функции обработки бинарного файла
void work(void)
{ int number; FILE * f; int nom_max, max;
int zero = 0;int i = 0;
if ((f = fopen("D:\\file.dat","r+b"))!= NULL)
{ fread(&max,sizeof(int),1,f);
nom_max = 0; i++;
while (fread(&number,sizeof(int),1,f))
{ if (number > max)
{ max = number; nom_max = i;
}
i++;
}
fseek(f,nom_max*sizeof(int),SEEK_SET);
fwrite(&zero,sizeof(int),1,f);
fclose(f);
} else printf("Error open file!\n");
}

29.

Файлы (С++)

30.

Файлы (С++ )
Синтаксис объявления потоков:
#include <fstream.h>
ifstream имя_потока; // файловый поток ввода
ofstream имя_потока; // файловый поток вывода
fstream имя_потока; // файловый поток ввода и вывода
Прототип функции open():
void open(const char *name, int mode);
Режимы (mode) открытия файла:
ios::out – открытие файла для вывода;
ios::in – открытие файла для ввода;
ios::app – вводимые данные добавляются в конец файла;
ios::ate – вызывает поиск конца файла в момент открытия файла
ios::binary – открытие файла для бинарных операций.
ios::nocreate – когда открыт может быть только существующий файл;
ios::noreplace – невозможно открыть файл если он уже создан ранее
ios::trunk – уничтожение содержимого существующего файла до нуля
Синтаксис вызова функции open():
имя_потока.open(<фактические параметры>);

31.

Файлы (С++ )
В С++ для работы с файлами используются специальные потоки. Ресурсы работы с файловыми
потоками находятся в заголовочном файле fstream.h.
В С++ используется три класса потоков: ввода, вывода и ввода-вывода.
После объявления потока его связывают с файлом с помощью функции open().
При вызове функции open() используется конструкция составного имени, так как функция open()
является методом класса ios.

32.

Файлы (С++ )
Синтаксис определения файлового потока для вывода данных в файл:
Синтаксис определения файлового потока для ввода данных из файла:
ofstream имя_потока(имя_файла,ios::app);
Синтаксис чтения данных из файла:
ifstream имя_потока(имя_файла,ios::in);
Синтаксис определения файлового потока для добавления данных в конец
файла:
ofstream имя_потока(имя_файла,ios::out);
Файловый_поток >> имена_переменных;
Синтаксис вывода данных в файл:
Файловый_поток << выводимые_данные;

33.

Файлы (С++ )
Можно производить связывание потока с именем файла сразу при его определении. При этом
сразу после имени потока указывается список фактических параметров.
Закрытие файлового потока выполняется с помощью встроенной функции close().
При вызове функции close() используется конструкция составного имени, так как функция close()
является методом класса ios.
Ввод и вывод данных из (в) файла производится соответственно с помощью операторов
извлечения (>>) и передачи данных в поток (<<).
Синтаксис чтения данных из файла аналогичен потоку cin. Синтаксис вывода данных в файл
аналогичен потоку cout.
Замечание: Если в текстовом файле хранятся числовые значения, то после последнего числа не
должно быть пробелов, символов табуляции и конца строки.

34. Ввод – вывод элементов массива

Чтение элементов одномерного массива из текстового файла и
запить в текстовый файл (С++):
#include <iostream>
#include <fstream>
using namespace std;
int main(void)
{ int n = 0; int a[10];
ifstream f; // объявление потока для чтения
f.open("D:\\abc1.txt"); // режим ios::in
if (f) { cout << "Read file ! \n";
while(!f.eof())
{ f >> a[n]; // чтение из файла
n++;
} f.close();
for(int i=0;i < n;i++)
cout << a[i] << " ";
}
else cout << "File not found \n";

35. Ввод – вывод элементов массива

ofstream f2; // объявление потока для записи
f2.open("D:\\abc2.txt"); // режим ios::out
if (f)
{ for(int i = 0;i < n;i++)
f2 << a[i] << " "; // запись в файл
cout << "\nFile write!";
f2.close();
}
else cout << "File not found \n";
}

36.

Файлы (С++ )
Контрольные вопросы
1.
2.
3.
4.
5.
6.
Понятие файла и потока. Понятие текстовых и бинарных файлов.
Открытие файлов в языке С: синтаксис, семантика, примеры.
Функции ввода - вывода языка С для обработки текстовых файлов:
синтаксис, семантика, примеры.
Функции ввода - вывода языка С для обработки бинарных файлов:
синтаксис, семантика, примеры использования.
Произвольный доступ к элементам двоичных файлов в языке С:
синтаксис используемых функций, примеры.
Как организуется работа с файлами и потоками в стиле языка С++ (на
примере текстовых файлов).
English     Русский Rules