ЛЕКЦИЯ 11 Работа с файлами Си
1. Введение в работу с файлами
1.2 Буфер ввода/вывода
2. Файловый ввод/вывод в С и функции библиотеки <stdio.h>
2.2 Функции для работы с файлами
7. Управление буфером ввода/вывода
Буферизированный вывод
3. Бинарные файлы
2.43M
Категория: ПрограммированиеПрограммирование

11. Лекция 11. Файлы_Полная (9)

1. ЛЕКЦИЯ 11 Работа с файлами Си

Структура FILE
1

2. 1. Введение в работу с файлами

Файловая система - структура,
определяющая способ организации,
хранения, доступа к данным на
устройствах хранения. Позволяет
операционной системе и программам
обращаться и выполнять операции
над файлами при взаимодействии
программ и физических устройств
ввода/вывода.
Примеры файловых систем
– FAT32 (File Allocation Table),
NTFS (new technology file
system), которые используются
операционными
системами
семейства Windows.
Мой компьютер – > ПКМ на диск – > Свойства
2

3.

Что такое файл?
Файлы - это логическая концепция, применимая ко всему,
начиная от дисковых файлов и заканчивая терминалами
Физический файл – именованная область памяти на
внешнем носителе, используемая для долговременного
хранения некоторой логически связанной информации.
Файл
в
языке
С/С++
последовательность байтов.
-
неструктурированная
Ввод/вывод в С/С++ реализован с помощью потоков. Мы
работали со стандартными потоками – ввод с клавиатуры, вывод
на экран монитора.
Разные устройства хранения и передачи данных (диски,
принтер, коммуникационные каналы) физически отличаются друг
от друга. Файловая система преобразует их в единое
абстрактное логическое устройство, называемое потоком
(файл с предоставленными средствами буферизации).
Библиотека <stdio.h> - библиотека буферизированного
обмена, позволяющая работать с текстовыми файлами
3

4.

Текстовый поток — последовательность символов, строк
текста. При передаче символов из потока на экран часть из них не
отображается (символ перевода строки, возврата каретки).
Двоичный поток — последовательность байтов, однозначно
соответствующих байтам на внешнем устройстве.
При выполнении программы автоматически открываются
потоки:
стандартный ввод (stdin)
стандартный вывод (stdout)
стандартный вывод для сообщений об ошибках (stderr)
4

5.

Поток связывается с определенным файлом при выполнении
операции его открытия, после чего можно выполнять обмен данными
между файлом и программой. При этом вся информация о файле
содержится в структуре типа FILE, и для работы с файлом нужно
объявить указатель на структуру FILE.
FILE* f; //структура FILE определена в stdio.h
Потоковый ввод-вывод — обмен данными между программой и
внешним файлом производится не по 1 байту, а блоками. При
открытии файла (с помощью функции fopen()) создается буфер (с
помощью malloc()) в оперативной памяти. Размер буфера 512 или
1024 байт, определен в константе BUFSIZ :
#define BUFSIZ 512 //определена в stdio.h
Таким образом за одно обращение к устройству (файлу)
производится считывание или запись фиксированной порции данных
в буфер ОП.
5

6.

6

7.

1.1 Библиотека С, поддерживающая обмен данными
на уровне потока
В С/C++ нет встроенных средств для работы с файлами,
начиная с ввода/вывода информации. Все необходимые
действия выполняются с помощью функций, включенных в
стандартные библиотеки.
#include <stdio.h> // язык С
#include <iostream> // язык C++
extern FILE* stdin;
extern FILE* stdout;
extern FILE* stderr; // в современной системе
//в библиотеке stdio.h не найдете такого объявления
7

8.

Работа со стандартными потоками – клавиатурой и монитором
scanf("%d", &x); эквивалентно fscanf(stdin, "%d", &x);
printf("%d", x); эквивалентно fprintf(stdout,"%d", x);
//при отладке вывод информации на экран вместо файла
int x;
FILE* f_stdin = stdin;
FILE* f_stdout = stdout;
fprintf(f_stdout, "------> x=");
fscanf(f_stdin, "%d", &x);
fprintf(f_stdout, "------> x=%3d", x);
fflush(stdin);
//очистка буфера при вводе
// с клавиатуры
fflush(stdout); //содержимое буфера записывается
//в соответствующий файл
8

9. 1.2 Буфер ввода/вывода

В заголовочных файлах stdio.h объявлен размер буфера:
#define BUFSIZ
//или
#define BUFSIZ
512
1024
BUFSIZ задает размер буфера потока, кратного величине
логического блока файловой системы.
файл
УВВ
Вывод из файла на
устройства ввода/вывода
буфер
Буферизация ввода/вывода осуществляется автоматически и
позволяет ускорить выполнение программы за счёт
уменьшения количества обращений к медленно работающим
внешним устройствам.
9

10.

Вводим данные из внешнего файла:
Символ
конца
файла
int x;
FILE* fp = fopen("NameFile", "r");
Внешний файл с именем NameFile , числа записаны через пробел
123 456789
987654321 .
.
fp
буфер
1
.
123 456789
987654 . . .
*
1
x
1
программа
512 байт
экран
fscanf(fp,"%d", &x);
1
10

11.

Еще раз про Данные, Потоки, связь с файлами, ввод/вывод:
данные читаются из файлов и с устройств и пишутся в файлы и на
устройства;
данные передаются побайтно или группами байтов;
данные рассматриваются как неструктурированный набор данных –
поток с предоставленными средствами буферизации.
В языке С в библиотеке stdio.h объявлен тип-структура
FILE и функции работы с файлами. Поток связывается с
конкретным файлом с помощью операции открытия fopen(), и
обмен между файлом и программой выполняется через буфер.
Функции буферизованного ввода-вывода (printf, scanf) не
выполняют проверок на соответствие аргументов форматной строке.
В языке
С++
есть набор классов для управления
вводом/выводом. Для работы с файлами необходимо подключить
заголовочный файл <fstream>, в котором определены еще
несколько классов, и файловый ввод/вывод реализуется через
объекты классов <ifstream> – файловый ввод и <ofstream> –
файловый вывод. Подробнее про потоки во 2м семестре, в С++. 11

12.

1.3 Тип FILE – немного истории
FILE – тип данных (struct), определяет поток и содержит
информацию, необходимую для управления потоком, в том
числе указатель на буфер потока, и его показатели состояния.
#include <stdio.h>
//В BorlandC - 1990, 1-я версия для DOS, в 1993 - для Windows
typedef struct {
int
level;
// fill/empty level of buffer
unsigned
flags;
// File status flags
char
fd;
// File descriptor
unsigned char hold;
// Ungetc char if no buffer
int
bsize;
// Buffer size
unsigned char _FAR* buffer; // Data transfer buffer
unsigned char _FAR* curp;
// Current active pointer
unsigned
istemp;
// Temporary file indicator
short
token;
// Used for validity checking
} FILE;
// This is the FILE object
Можно было манипулировать напрямую полями структуры. Но при смене
оборудования, архитектуры разработанное ранее ПО перестает работать! 12

13.

#include <stdio.h>
//В MS VisualC до 11 версии – С++ 11 относится к Visual Studio 2012
struct _iobuf {
char* _ptr;
int
_cnt;
char* _base;
int
_flag;
int
_file;
int
_charbuf;
int
_bufsiz;
char* _tmpfname;
};
typedef struct _iobuf FILE;
FILE* f;//указатель на структуру FILE
13

14.

#include <stdio.h>
//В Microsoft C структура FILE
//(Visual Studio 2019)
typedef struct _iobuf
{
void* _Placeholder; //пустой указатель!
} FILE;
Нет фактических полей структуры!!!, единственный член void*, который фактически указывает на секретную структуру,
расположенную глубоко в реализации Microsoft C. Реализация
структуры скрыта от пользователей библиотеки (инкапсуляция).
Фактически мы объявляем указатель на непрозрачную структуру.
FILE* f;
Клиентской программе предоставляется способ хранения
ссылки на объект, управляемый API (Application programming
interface), не раскрывая ничего о реализации этого объекта, кроме
его адреса в памяти (самого указателя).
В MS Visual C++ с версии 2022 и дальше поищите информацию о
структуре FILE
14

15.

Некоторые объявления библиотеки stdio.h
для работы с файлами
#include <stdio.h> //файл содержит следующие определения
#define BUFSIZ
512
#define EOF
(-1)
#define _IOFBF 0x0000
#define _IOLBF 0x0040
#define _IONBF 0x0004
#define SEEK_CUR
#define SEEK_END
#define SEEK_SET
#define FILENAME_MAX
#define FOPEN_MAX
#define _SYS_OPEN
// режим буферизации,
// используется в функции setvbuf
1
2
0
260
20
20
15

16.

Структура физического файла
байт
байт
байт
байт
байт
байт
байт
. . .
Структура логического файла – это способ восприятия
дискового файла в программе с помощью шаблона (типа
компонент файла), через который воспринимается физическая
структура его информации.
При вводе данных форматируем данные к типу char
код символа
код символа
код символа
код символа
код символа
код символа
. . .
EOF
При вводе данных форматируем данные к типу short int
код целого
со знаком
код целого
со знаком
код целого
со знаком
.
.
.
EOF
16

17. 2. Файловый ввод/вывод в С и функции библиотеки <stdio.h>

2. Файловый ввод/вывод в С и
функции библиотеки <stdio.h>
1. Включение библиотеки <stdio.h> , объявление в программе
указателей на структуру FILE (FILE* f1, *f2;)
2. Открытие файла вызовом функции fopen, присвоение
возвращаемого ею значения указателю на структуру FILE
FILE* f = fopen("Data.txt", "r");
3. Проверка правильности открытия файла (указатель файла
после шага 2 не должен равняться NULL)
4. Чтение и запись в файл с помощью функций fprintf, fscanf,
fputs, fgets, fgetc, fputc, getc, putc, fread, fwrite и других,
объявленных в библиотеке <stdio.h>
5. Закрытие файла вызовом функции fclose
fclose(f);
17

18.

2.1 Открытие и закрытие файлов
FILE* f = fopen("Data.txt", "r");
При открытии файла ему в соответствие ставится поток,
обеспечивающий передачу данных между файлами и программами.
Стандартный поток ввода stdin позволяет программе считывать
данные с клавиатуры, а стандартный поток вывода stdout - выводить
данные на экран.
Функция fopen() возвращает указатель на структуру FILE, которая
содержит информацию, используемую при работе с файлом. Эта
структура содержит поля для хранения информации о текущем
указателе буфера ввода-вывода, текущем счетчике байтов, базовом
адресе буфера ввода-вывода, типе файла, дескрипторе файла и другой
информации, необходимой для реализации операций по обработке
файла.
После работы с файлом его нужно закрыть. Почему?
для записи последних данных из буфера в файл
файл может быть не доступен другим программам для чтения из него
есть ограничение на число одновременно открытых файлов
fclose(f);
18

19. 2.2 Функции для работы с файлами

1. Открытие потока
FILE* fopen(const char* name, const char* mode);
Режим открытия mode файла функцией fopen:
“r”
- открытие текстового файла на чтение;
“w” - создание нового текстового файла на запись;
“a” - открытие текстового файла для добавления (записи в конец потока);
“rb” - открытие двоичного файла на чтение;
“wb” - создание нового двоичного файла на запись;
“ab” - открытие двоичного файла для добавления;
“r+” - открытие существующего текстового файла на чтение и запись;
“w+” - создание нового текстового файла на чтение и запись;
“a+” - открытие текстового файла на чтение и запись (в конец потока);
”rb+” - открытие двоичного файла на чтение и запись;
“wb+” - создание нового двоичного файла на чтение и запись;
“ab+” - открытие двоичного файла на чтение и добавление в конец файла.
2. Закрытие потока
int fclose(FILE* f);
В случае успеха fclose() возвращает 0, в противном случае —1.
19

20.

3. Форматированный ввод/вывод
int fprintf(FILE* f, const char* format, …);
int fscanf(FILE* f, const char* format[, par1, par2, …]);
#define _CRT_SECURE_NO_WARNINGS
Обязательно, если stdio.h
#include <stdio.h>
int main(void)
{int x;
FILE* fp = fopen("Numbers", "w");
while (!feof(stdin)) {
//истинно, если достигнут ^Z
scanf("%d\n", &x);
//Ввод чисел в переменную х
fprintf(fp, "%3d", x); //Вывод (запись) чисел в файл
}
fclose(fp);
fp = fopen("Numbers", "r");
while (!feof(fp)) {
//Пока не достигнут конец файла
fscanf(fp, "%d", &x); //Ввод чисел (чтение) из файла в х
printf("%3d", x);
//Отображение х на экране
}
fclose(fp);
Проверка достижения конца файла
return 0;
}
int
feof(FILE* f);//EOF в случае ошибки 20

21.

4. Ввод/вывод символьных строк
Возвращает NULL
в случае ошибки
char* fgets(char* str, int n, FILE* f);
Возвращает EOF
int fputs(char* str, FILE* f);
в случае ошибки
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
char str[80];
FILE* f = fopen("Data", "w");
fputs("aaaaaa",f);
fputs("bbbbbbbbb",f);
fputs("cccccccccccccccc",f);
fclose(f);
f = fopen("Data", "r");
while (!feof(f))
{ fgets(str, 80, f);
puts(str);
}
fclose(f);
_getch();
}
Построчный вывод в
файл не добавляет в
конец строки '\n'
21

22.

int main(void)
{
char str[80];
FILE* f = fopen("Data", "w");
fputs("aaaaaa",f);
fputs("bbbbbbbbb",f);
fputs("cccccccccccccccc",f);
fclose(f);
Лучше писать так
f = fopen("Data", "r");
while (fgets(str, 80, f)!=NULL)
{
puts(str);
}
_getch();
fclose(f);
return 0;
}
22

23.

Если хотим разделить на строки, то добавляем символ новой строки
int main(void)
{
char str[80];
FILE* f = fopen("Data.txt", "w");
fputs("aaaaaa\n",f);
fputs("bbbbbbbbb\n",f);
Пишет конец строки,
который читается fgets
fputs("cccccccccccccccc",f);
как пустая строка
fclose(f);
f = fopen("Data.txt", "r");
while (fgets(str, 80, f) != NULL)
{
puts(str);
}
_getch();
fclose(f);
return 0;
}
23

24.

5. Посимвольный ввод/вывод
int fgetc(FILE* f);
int fputc(int ch, FILE* f);
void main() {
int c;
while ((c = fgetc(stdin)) != EOF) {
fputc(c, stdout);
}
}
6. Ввод/вывод блоками (3-я Лабораторная работа)
size_t fread(void* buf, size_t size, size_t, FILE * f);
size_t fwrite(const void* buf, size_t size, size_t n,
FILE * f);
buf – указатель на блок данных
size – размер блока данных
count – сколько блоков читаем/записываем в файл
24

25.

6.1 Ввод/вывод блоками, пример для типа struct
(3-я Лабораторная работа)
struct book {
char title[80];
int price;
} library;
int main(void)
{
FILE* f = fopen("library.dat", "w");
scanf("%s %d", library.title, &library.price);
fwrite(&library, sizeof(book), 1, f);
fclose(f);
f = fopen("library.dat", "r");
fread(&library, sizeof(book), 1, f);
printf("%s %d", library.title, library.price);
fclose(f);
_getch();
return 0;
}
25

26.

#define N 4
6.2 Пример простой программы для выполнения
лабораторной работы №3 – файл структур
ВНИМАНИЕ!
Код 3-й лабораторной работы должен содержать
функции, такие, как:
- Создание файла
- Вывод информации из файла на терминал
- Поиск заданной информации в файле
- Добавление информации в файл
- Корректировка информации в файле
int main() {
FILE* f;
typedef struct {
char name[20];
int grade[N];
} stud;
stud p[10];
int num;
const char name[12] = "24-IST-1-1";
printf("\nnumber of students:");
scanf("%d", &num);
if ((f = fopen(name, "w")) == NULL) exit(1);
printf("\nEnter the students'\n names and %d exam grades:\n",
N);
for (int i = 0; i < num; i++)
{
scanf("%s", p[i].name);
for (int k = 0; k < N; k++)
scanf("%d", &p[i].grade[k]);
fwrite(&p[i], sizeof(p[i]), 1, f);
}
26

27.

f = fopen(name, "r");
printf("\nstudents' names\texam grades\n");
int i = 0;
while (fread(&p[i], sizeof(p[i]), 1, f))
{
printf("\n%10s", p[i].name);
for (int k = 0; k < N; k++)
printf("%5d", p[i].grade[k]);
}
fclose(f);
_getch();
return 0;
}
27

28.

6.3 Ввод/вывод блоками, пример создания временного файла,
куда записываем массив
void main(void)
{ int array[20];
FILE* tempf = tmpfile(); //создать временный файл
if (!tempf) {
Получаем
puts("нельзя открыть временный файл"); исключение:
Run-Time Check
exit(1);
?
Failure #2 }
Stack around the
variable 'array'
//заполнение массива
for (int i = 0; i < 20; i++, array[i] = i); was corrupted.
fwrite(array, sizeof(int), 1, tempf); //пишем в файл
rewind(tempf); //указатель вернуть на начало
fread(array, sizeof(int), 20, tempf);
Где ошибка?
//вывод массива
for (int i = 0; i < 20; i++, printf("%3d",array[i]));
puts("");
_rmtmp(); //закрыть и уничтожить временный файл
}
28

29.

Устранили одну ошибку выхода за пределы индексов, при выводе
последнего значения массива – опять ошибка!
void main(void) {
int array[20];
FILE* tempf = tmpfile(); //создать временный файл
if (!tempf) {
puts("нельзя открыть временный файл");
exit(1);
Поменяли местами, иначе был
выход за пределы индексов
}
//заполнение массива
for (int i = 0; i < 20; array[i] = i, i++);
fwrite(array, sizeof(int), 1, tempf); //пишем в файл
rewind(tempf); //указатель вернуть на начало файла
fread(array, sizeof(int), 20, tempf);
//вывод массива
for (int i = 0; i < 20; i++, printf("%3d",array[i]));
puts("");
_rmtmp(); //закрыть и уничтожить временный файл
}
29

30.

Устранили одну ошибку выхода за пределы индексов, при выводе
последнего значения массива – опять ошибка!
void main(void) {
int array[20];
FILE* tempf = tmpfile(); //создать временный файл
if (!tempf) {
puts("нельзя открыть временный файл");
exit(1);
Поменяли местами, иначе был
выход за пределы индексов
}
//заполнение массива
for (int i = 0; i < 20; array[i] = i, i++);
fwrite(array, sizeof(int), 1, tempf); //пишем в файл
rewind(tempf); //указатель вернуть на начало файла
fread(array, sizeof(int), 20, tempf);
//вывод массива
for (int i = 0; i < 20; i++, printf("%3d",array[i]));
puts("");
_rmtmp(); //закрыть и уничтожить временный файл
}
30

31.

Устранили вторую ошибку выхода за пределы индексов
void main(void) {
int array[20];
FILE* tempf = tmpfile(); //создать временный файл
if (!tempf) {
puts("нельзя открыть временный файл");
exit(1);
}
//заполнение массива
for (int i = 0; i < 20; array[i] = i, i++);
fwrite(array, sizeof(int), 1, tempf); //пишем в файл
rewind(tempf); //указатель вернуть на начало
fread(array, sizeof(int), 20, tempf); Также поменяли местами
//вывод массива
for (int i = 0; i < 20; printf("%3d",array[i]), i++);
puts("");
_rmtmp(); //закрыть и уничтожить временный файл
}
31

32. 7. Управление буфером ввода/вывода

#define BUFSIZ
512
Можно управлять размером буфера:
void setbuf(FILE* f, char* p);
//f –
//p –
указатель на структуру FILE,
указатель на устанавливаемый буфер
void setvbuf(FILE* f, char* p, int mode, size_t size);
//size – размер буфера,
//mode – параметр(целое), устанавливающий режим:
//_IOFBF(полная буферизация),
//_IOLBF(для вывода – построчная буферизация, т.е.
//опустошение буфера при записи в буфер символа новой строки)
//_IONBF(запрет буферизации)
int
fflush(FILE* f); //очистка буфера, вывод содержимого
//буфера на физическое устройство
32

33. Буферизированный вывод

#define _CRT_SECURE_NO_WARNINGS
Буферизированный вывод
#include <stdio.h>
#include <conio.h>
int main(void)
{
char buf[BUFSIZ]=""; // BUFSIZ определено в stdio.h
setbuf(stdout, buf);//назначить строку-буфер стандартному потоку
// поместить в буфер символы
puts("It is the test of a buferizovanny conclusion.\n");
puts("This conclusion is carried out in buf\n");
puts("and you will see nothing, while the buffer"
"won't be filled\n");
puts(" or you won't dump it.\n");
_getch(); //показали, что вывод идет в назначенный буфер, не на экран
//сбросить поток для отображения на экране
fflush(stdout);
return 0;
}
Вместо буфера, по умолчанию выделенного системой для данного потока, для
буферизации ввода-вывода используется указанный пользователем буфер.
Запустили программу на выполнение. Экран пуст!
Нажимаем любую клавишу – текст выводится на экран!
33

34.

Теперь введем символов больше 512,
т.е. полностью заполняется буфер в 512 байт
и остается еще текст
int main(void)
{
char buf[BUFSIZ]="";
setbuf(stdout, buf); //назначить буфер стандартному потоку
puts("It is the test of a buferizovanny conclusion.\n");
puts("This conclusion is carried out in buf\n");
puts("and you will see nothing, while the buffer"
"won't be filled\n");
puts(" or you won't dump it.\n");
// увеличим количество выводимых в буфер символов
puts("Fill the buffer up to 512 bytes by writing the text\n\
11111111111111111111111111111111111111111111111111111\n\
11111111111111111111111111111111111111111111111111111\n\
11111111111111111111111111111111111111111111111111111\n\
11111111111111111111111111111111111111111111111111111\n\
11111111111111111111111111111111111111111111111111111\n\
111111111111111111111111111111111111111111 end of text");
_getch();
fflush(stdout);
return 0;
}
//сбросить поток
Добавили еще несколько
строк текста, закончив его
фразой end of text
34

35.

Часть текста выведена. Нажимаем любую клавишу – выводится остаток текста. Так
почему в предыдущем случае текст не выводился, а здесь часть текста выведена?
При полном
заполнении буфера
его содержимое
выводится в поток и
в буфер помещается
следующая порция
информации.
Getche() ждет
нажатия клавиши и
fflush() освобождает
буфер.
35

36.

int main(void)
{
char buf[BUFSIZ]="";
setbuf(stdout, buf); //назначить буфер стандартному потоку
// увеличим количество выводимых в буфер символов
puts("It is the test of a buferizovanny conclusion.\n");
puts("This conclusion is carried out in buf\n");
puts("and you will see nothing, while the buffer"
"won't be filled\n");
puts(" or you won't dump it.\n");
puts("Fill the buffer up to 512 bytes by writing the text\n\
11111111111111111111111111111111111111111111111111111\n\
11111111111111111111111111111111111111111111111111111\n\
11111111111111111111111111111111111111111111111111111\n\
11111111111111111111111111111111111111111111111111111\n\
11111111111111111111111111111111111111111111111111111\n\
111111111111111111111111111111111111111111 end of text");
//уберем _getch(); весь поток выводится, не видим буферизации
fflush(stdout);//сбросить поток
}
Таким образом, можно управлять выводом, т.е. выводить
информацию порциями, к тому же одинаковыми по размеру
36

37.

8. Работа с позицией в файле
Для каждого файла после его открытия определяется индикатор позиции,
который указывает на смещение от начала файла в байтах. Тип индикатора
позиции определяется как
typedef
long
fpos_t;
Установка индикатора позиции на начало файла
void
rewind(FILE* f);
(при этом сбрасывается индикатор ошибки и конца файла).
Установка индикатора позиции файла в позицию, на которую указывает
параметр pos
int
fsetpos(FILE* f, const
fops_t* pos);
Записывает текущую позицию файла по адресу pos
int
fgetpos(FILE* f, const
fops_t* pos);
Проверка достижения конца файла
int
feof(FILE* f);
//EOF в случае ошибки
37

38.

Перемещение текущей позиции в файле, связанном с потоком f,
относительно org на количество байтов, указанное в аргументе k
int
fseek(FILE* f, long k, int org);
Значение org :
SEEK_CUR - от текущей позиции
#define SEEK_CUR
SEEK_END - от конца файла
#define SEEK_END
#define SEEK_SET
SEEK_SET - от начала файла
1
2
0
возвращение текущей позиции в файле, в случае ошибки –
отрицательное значение - 1L.
long
int ftell(FILE * f);
38

39.

9. Работа с ошибками
int
ferror(FILE * f);
возвращает код ошибки при работе с потоком, в случае отсутствия
ошибки – значение 0.
int clearerr(FILE * f);
очищает флаги ошибок для потока f. После возникновения ошибки
работа с файлами возможна только после сброса ошибки с помощью
функций clearerrr и rewind.
10. Переименование файла
int
rename(const char* old_name, const char* new_name);
11. Удаление файла
int remove(const char *fname);
39

40. 3. Бинарные файлы

Текстовые файлы хранят информацию в виде, понятном человеку,
и данные из них вводятся в переменные последовательно. Например,
при записи в текстовый файл числа 12345678 будет записано 8
символов, т.е. 8 байт данных, это текст. При вводе этих данных в целое
число в памяти программы символьная строка преобразуется в 4-х
байтовое значение и уже представляет собой число.
Таким образом, при вводе данных строка из цифр форматируется в
число, а при выводе число преобразуется и отражается на экране или
записывается в текстовый файл как строка. Это затратно.
В бинарных файлах содержимое – последовательность байт, с
возможностью непосредственного обращения – произвольного доступа
к любой его части.
Функции
двоичного
ввода/вывода
fread()
и
fwrite() переносят содержимое памяти в двоичный файл без каких
либо преобразований, данные хранятся в нем и читаются в том же
самом
порядке.
К
данным
бинарного
файла
возможен
последовательный и прямой доступ (с помощью функции fseek()).
Бинарный файл хранит данные в бинарном виде, визуально не
понятном человеку.
40

41.

4. Дополнительные слайды (№41 – 45)
Еще раз про стандартные библиотеки ввода/вывода, и наследовании
стандартных библиотечных функций в С++ от языка С
1. В MS VS есть функции scanf_s(), printf_s(), fscanf_s(),
fprintf_s(), fopen_s, . . ., которые лучше не
использовать, так как они включены в стандарт как
рекомендуемые, есть не во всех компиляторах (есть в VS),
прототипы которых отличаются от функций scanf(), printf(),
fscanf(), fprintf(), fopen() . . ., например
FILE* fopen(
const char* filename,
const char* mode
);
https://learn.microsoft.com/ru-ru/cpp/c-runtimelibrary/reference/fopen-wfopen?view=msvc-170
errno_t fopen_s(
FILE** pFile,
const char* filename,
const char* mode
);
https://learn.microsoft.com/ru-ru/cpp/cruntime-library/reference/fopen-s-wfopens?view=msvc-170
2.Библиотека <cstdio> включает библиотеку <stdio.h>.
Использование библиотеки <cstdio> гарантирует объявление всех
имен в пространстве std (а это уже С++)
41

42.

3.1 Пример использования функций fopen_s,
#include <stdio.h>
scanf_s, fcanf_s, fprintf_s
int main(void)
{
int x;
FILE* fp;
fopen_s(&fp, "Numbers", "w");
while (!feof(stdin)) {
scanf_s("%d\n", &x);
Где хранится созданный файл
fprintf_s(fp, "%3d", x);
Numbers ?
}
C:\Users\Admin\source\repos\
fclose(fp);
Project_File\Project_File
}
fopen_s(&fp,"Numbers", "r");
while (!feof(fp)) {
fscanf_s(fp, "%d", &x);
printf_s("%3d", x);
}
fclose(fp);
ПК->
Открыть с
return 0;
помощью ->
Блокнот
42

43.

3.2 Пример использования функций fopen_s,
#include <stdio.h>
scanf_s, fcanf_s, fprintf_s
int main(void)
{
int x;
FILE* fp;
fopen_s(&fp, "Numbers", "w");
while (!feof(stdin)) {
scanf_s("%d\n", &x);
fprintf_s(fp, "%3d", x);
}
fclose(fp);
fopen_s(&fp,"Numbers", "r");
while (!feof(fp)) {
fscanf_s(fp, "%d", &x);
printf_s("%3d", x);
}
Почему в блокноте и при выводе на
fclose(fp);
терминал имеем разные значения?
return 0;
}
43

44.

3.3 Пример использования функций fopen_s,
#include <stdio.h>
scanf_s, fcanf_s, fprintf_s
int main(void)
{
int x;
FILE* fp;
fopen_s(&fp, "Numbers", "w");
while (!feof(stdin)) {
scanf_s("%d\n", &x);
fprintf_s(fp, "%6d", x);
}
fclose(fp);
fopen_s(&fp,"Numbers", "r");
while (!feof(fp)) {
fscanf_s(fp, "%6d", &x);
printf_s("%3d", x);
}
fclose(fp);
Не забываем управлять форматом
вывода, задавая ширину поля вывода
return 0;
}
44

45.

4. Если выдаются ошибки типа:
This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation,
use _CRT_SECURE_NO_WARNINGS. See online help for details.
для совместимости с классическими функциями, особенно при создании
консольных приложений, необходимо в самом начале программы вставить
директиву:
#define _CRT_SECURE_NO_WARNINGS
или заменить старые названия функций на их безопасные версии,
например, fopen на fopen_s , fprintf на fprintf_s и т.д. Индекс _s
в конце означает secure – безопасный.
При этом "классический" оператор открытия файла
FILE* out = fopen_s("data.txt", "wt");
нужно заменить на:
FILE* out;
fopen_s(&out, "data.txt", "wt");
Это связано с тем, что функции, возвращающие указатель, считаются
небезопасными, отсюда и изменившийся шаблон метода открытия файла.
45

46.

ВСЕ
46
English     Русский Правила