Similar presentations:
op3
1. Основы программирования на c/c++ Лекция 3: Файлы.
oopCpp@yandex.ru1
2. План
Введение и фундаментальные понятия: Для чего нужны файлы,базовые операции, текстовый vs бинарный режим.
Часть 1: Объектно-ориентированный подход — <fstream>: Краткий
разбор классов, методов, примеры чтения, записи, позиционирования.
Часть 2: Процедурный подход — <stdio.h> (fopen): Изучение
функций, работа с указателями на файл, тонкости использования.
Часть 3: Низкоуровневый подход — WinAPI: Максимальный
контроль и производительность средствами операционной системы.
Сравнительный анализ и заключение: Детальное сравнение трех
подходов, рекомендации по применению, выводы
2
3. Файл как основа целостности
Файл представляет собой именованную область данных нафизическом носителе информации, таком как жесткий диск (HDD) или
твердотельный накопитель (SSD).
Эта область хранит информацию в виде последовательности байтов,
которая сохраняется после завершения работы программы, обеспечивая
тем самым постоянство данных (персистентность).
Каждый файл обладает набором атрибутов, включая имя, расширение,
путь к местоположению в файловой системе, размер, а также даты
создания и изменения. Понимание природы файла является первым
шагом к эффективной работе с данными на диске.
3
4. Базовые операции с файлами
Открытие файла:Это первоначальная операция, в процессе которой операционная
система устанавливает связь между вашей программой и файлом на
диске.
При открытии проверяются права доступа, выделяются системные
ресурсы и создается специальный объект (дескриптор или поток), через
который и будет происходить все дальнейшее взаимодействие.
Без успешного открытия файла любые попытки чтения или записи
обречены на провал, поэтому проверка результата открытия является
обязательной практикой.
4
5. Базовые операции с файлами
Чтение и запись:После успешного открытия программа может читать данные из файла
в оперативную память или записывать данные из памяти в файл.
Эти операции передачи данных между разными уровнями хранения —
быстрой, но энергозависимой оперативной памятью и медленной, но
постоянной дисковой подсистемой.
Эффективность выполнения этих операций критически важна для
производительности приложения, особенно при работе с большими
объемами информации, и сильно зависит от выбранного метода работы
с файлом.
5
6. Базовые операции с файлами
Позиционирование и закрытие:Позиционирование позволяет перемещаться по файлу, чтобы читать
или записывать данные в произвольном месте, а не только
последовательно с начала до конца.
Эта операция реализуется с помощью специальных функций или
методов, которые изменяют текущую позицию в файле.
Закрытие файла — это критически важная завершающая операция,
которая разрывает установленную связь, гарантированно сохраняет все
данные из буферов на диск и освобождает занятые системные ресурсы.
Не закрытый файл может привести к утечкам памяти и повреждению
данных.
6
7. Текстовые файлы
Текстовые файлы предназначены для хранения информации в форме,удобной для чтения человеком. Данные в них интерпретируются как
последовательности символов, организованные в строки, которые часто
разделяются символами перевода строки.
Ключевой особенностью текстовых файлов является использование
кодировок (например, ASCII, UTF-8, Windows-1251), которые определяют
соответствие между числовыми кодами и символами.
Примеры текстовых файлов включают исходный код программ (*.cpp,
*.h), файлы конфигураций (*.ini, *.json), логи и обычные документы (*.txt).
7
8. Бинарные файлы
Бинарные файлы хранят данные в том виде, в каком онипредставлены в оперативной памяти программы, без какого-либо
преобразования в символьные представления. Они содержат
последовательность байтов, и их структура понятна только программе,
которая их создала.
Бинарные файлы используются для эффективного хранения любых
данных, не являющихся чисто текстовыми: исполняемые программы
(*.exe, *.dll), изображения (*.jpg, *.png), аудиофайлы (*.mp3), а также
любые специализированные форматы данных приложений (*.dat). Их
главное преимущество — скорость чтения/записи и компактность.
8
9. Выбор режима: текст vs бинарный
Выбор между текстовым и бинарным режимом является одним изсамых важных проектных решений при работе с файлами.
Текстовый режим следует использовать, когда данные должны быть
удобочитаемы или редактируемы человеком, либо когда они должны
быть переносимы между системами с разными архитектурами.
Бинарный режим незаменим для максимальной производительности,
компактности хранения и работы со сложными структурами данных.
Ошибка в выборе режима (например, открытие бинарного файла в
текстовом режиме) может привести к порче данных из-за нежелательных
преобразований символов.
9
10. Потоки данных (Streams):
Поток данных (stream) — это фундаментальная абстракция,представляющая собой последовательность байтов, перемещающуюся
от источника к приемнику. Эта абстракция позволяет унифицировать
интерфейс для работы с различными устройствами ввода-вывода:
файлами, стандартной консолью, строками в памяти и сетевыми
соединениями.
Основное разделение происходит на входные потоки, используемые
для чтения данных, и выходные потоки, используемые для их записи.
Именно на этой абстракции построена вся современная система вводавывода .
10
11. <fstream>: кроссплатформенный стандарт
<fstream>: кроссплатформенныйстандарт
Заголовочный файл <fstream> является частью стандартной
библиотеки (stl) и предоставляет набор классов для объектноориентированной работы с файлами.
Эти классы инкапсулируют низкоуровневые системные вызовы
операционной системы, предоставляя программисту удобный,
безопасный и переносимый интерфейс.
Главным преимуществом данного подхода является его
кроссплатформенность: код, написанный с использованием <fstream>,
будет успешно компилироваться и работать на любой операционной
системе (Windows, Linux, macOS) без внесения изменений, что
значительно упрощает разработку и поддержку.
11
12. Пример
#include <fstream>#include <string>
int main() {
// Создаем объект выходного файлового потока
// и сразу открываем файл "log.txt".
// По умолчанию применяются флаги std::ios::out | std::ios::trunc.
std::ofstream
file ("log.txt");
// Проверяем, что файл действительно открылся и готов к работе.
if ( ! file.is_open()) {
// Выводим сообщение об ошибке в стандартный поток ошибок.
std::cerr << "Ошибка! Не удалось открыть файл!" << std::endl;
return 1; // Завершаем программу с кодом ошибки.
}
12
13. Пример
// … продолжение// Используем оператор << для записи данных в файл.
file << "Hello, File" << std::endl;
int value = 17;
file << value << std::endl;
// Явно закрываем файл.
// это хорошая практика для немедленного сохранения данных.
file.close();
return 0;
}
13
14. Пример 2: Чтение из текстового файла построчно
#include <fstream>#include <iostream>
#include <string>
int main() {
std::ifstream file("log.txt");
std::string line; // Переменная для хранения считанной строки.
// Проверяем статус открытия файла с помощью приведения к bool.
if (file) {
// Функция std::getline читает данные из потока 'file' до символа
// перевода строки и помещает результат в строку 'line'.
// Цикл продолжается, пока getline успешно считывает данные.
while (std::getline(file, line)) {
// Выводим считанную строку на стандартный вывод (консоль).
std::cout << "Прочитано: " << line << std::endl;
}
14
15. Пример 2: Чтение из текстового файла построчно
// … продолжение} else {
std::cerr << "Ошибка открытия файла!" << std::endl;
}
// Закрытие файла произойдет автоматически при разрушении объекта
'file'.
return 0;
}
15
16. Особенности бинарного режима
Проблема текстового режима в Windows:В текстовом режиме происходит невидимое для программиста
преобразование символов. В частности, при записи символа перевода строки
\n (LF, код 10) он преобразуется в последовательность \r\n (CRLF, коды 13 10).
При чтении последовательность \r\n, наоборот, преобразуется обратно в \n.
Это исторически сложившееся поведение для совместимости с разными ОС.
Однако для не-текстовых данных (картинки, EXE-файлы) такое
преобразование катастрофически портит данные.
16
17. Особенности бинарного режима
#include <fstream>// Простая структура, представляющая данные для сохранения.
struct Person {
char name[50]; // Фиксированный размер поля.
int age;
double height;
};
int main() {
Person p = {“Ivan Ivanov", 20, 185.5}; // Инициализируем структуру.
// Ключевой момент: используем флаг std::ios::binary.
std::ofstream file("person.dat", std::ios::binary);
17
18. Особенности бинарного режима
// … продолжениеif (file) {
// Метод write() записывает блок сырых байтов.
// Первый аргумент: указатель на начало блок памяти (адрес структуры p).
// Второй аргумент: количество байтов для записи (размер структуры).
file.write( reinterpret_cast<char*>(&p), sizeof (Person) );
}
// Важное предупреждение: такой способ не переносим между разными
// компиляторами и платформами
// из-за различий в выравнивании и размерах типов.
return 0;
}
18
19. Чтение в бинарном режиме
#include <fstream>#include <iostream>
struct Person {
char name[50];
int age;
double height;
};
int main() {
Person p; // Создаем объект, в который будем считывать данные.
std::ifstream file("person.dat", std::ios::binary); // в бинарном режиме.
if (file) {
// read читает блок байтов из файла и помещает его по указанному адресу.
file.read(reinterpret_cast<char*>(&p), sizeof(Person));
19
20. Чтение в бинарном режиме
// … продолжение// После чтения мы можем использовать данные из структуры.
std::cout << "Name: " << p.name << "\nAge: " << p.age
<< "\nHeight: " << p.height << std::endl;
} else {
std::cerr << "Файл не найден или не может быть открыт!" << std::endl;
}
return 0;
}
20
21. Позиционирование в файле: зачем нужно?
Часто возникает необходимость читать или записывать данные не в началоили конец файла, а в некоторое произвольное место. Например, обновить
запись о конкретном пользователе в середине большого файла базы данных.
Для этого необходимы функции, позволяющие управлять текущей позицией
— указателем, который определяет, где будет произведена следующая
операция чтения или записи. Это называется прямым или произвольным
доступом (random access).
21
22. Методы позиционирования в потоках
Для входных потоков (ifstream):tellg() — (tell get) возвращает текущую позицию указателя чтения.
seekg(pos) — (seek get) устанавливает указатель чтения на абсолютную
позицию pos.
seekg(offset, origin) — устанавливает указатель чтения относительно точки
origin на смещение offset.
Для выходных потоков (ofstream):
tellp() — (tell put) возвращает текущую позицию указателя записи.
seekp(pos) — (seek put) устанавливает указатель записи на абсолютную
позицию pos.
seekp(offset, origin) — устанавливает указатель записи относительно точки
origin на смещение offset.
22
23. Точки отсчета для позиционирования
Точки отсчета дляпозиционирования
• std::ios::beg — начало файла.
• std::ios::end — конец файла.
• std::ios::cur — текущая позиция в файле.
23
24. Пример : Определение размера файла через позиционирование
#include <fstream>#include <iostream>
int main() {
std::ifstream file("large_data.bin", std::ios::binary);
if (file) {
// Перемещаем указатель чтения на 0 байт от конца файла.
file.seekg(0, std::ios::end);
// tellg() возвращает текущую позицию, теперь она равна размеру файла.
std::streamsize fileSize = file.tellg();
// Возвращаем указатель в начало для последующего чтения.
file.seekg(0, std::ios::beg);
std::cout << "Размер файла: " << fileSize << " байт." << std::endl;
}
return 0;
}
24
25. Процедурный подход: <stdio.h>
Процедурный подход: <stdio.h>Заголовочный файл <cstdio> (унаследованный от C как stdio.h)
предоставляет набор процедурных функций для работы с вводом-выводом,
включая файловый.
Этот подход старше и более низкоуровневый, чем <fstream>, но все еще
широко используется, особенно в legacy-коде и в случаях, когда требуется
минимализм и прямой контроль.
В отличие от объектно-ориентированного подхода, здесь работа ведется не с
объектами-потоками, а с указателями на структуру FILE и набором
независимых функций, которые принимают этот указатель в качестве
аргумента.
25
26. Указатель на FILE и функция fopen
Указатель на FILE ифункция fopen
FILE*: Это указатель на структуру, которая содержит всю необходимую
информацию об открытом файле: его дескриптор, текущую позицию, буферы,
флаги ошибок и т.д. Программист работает исключительно с этим указателем,
не имея прямого доступа к содержимому структуры.
fopen: Функция для открытия файла. Принимает два аргумента: путь к файлу
(в виде строки типа const char*) и строку режима (например, "r", "w"). В случае
успеха возвращает переменную типа FILE*, в случае неудачи — NULL.
26
27. Строки режимов открытия файла в fopen
Строки режимов открытия файлав fopen
"r" — (read) открыть для чтения (файл должен существовать).
"w" — (write) открыть для записи (создает файл или перезаписывает
существующий).
"a" — (append) открыть для добавления в конец (создает файл, если не
существует).
"r+" — открыть для чтения и записи (файл должен существовать).
"w+" — открыть для чтения и записи (создает или перезаписывает файл).
"a+" — открыть для чтения и добавления (создает файл, если не существует).
Добавление "b" — открыть в бинарном режиме (например, "rb", "w+b").
27
28. Пример: Открытие и проверка в fopen
Пример: Открытие и проверкав fopen
#include <stdio.h> // Для FILE, fopen, fclose и т.д.
#include <iostream>
int main() {
// Открываем файл для записи в текстовом режиме.
FILE* file = fopen("data_c.txt", "wt");
// Критически важно проверить результат открытия!
if (file == nullptr) { // или if ( ! file)
std::perror("Ошибка открытия файла"); // Выводит сообщение об ошибке.
return 1;
}
// Файл открыт успешно, можно работать...
fclose(file); // ОБЯЗАТЕЛЬНО закрываем файл!
return 0; }
28
29. Функции чтения и записи
Для форматированного текстового ввода/вывода:fprintf(file, format, ...) — аналог printf, но вывод в файл.
fscanf(file, format, ...) — аналог scanf, но ввод из файла.
Для бинарного и построчного ввода/вывода:
fread(ptr, size, count, file) — читает count элементов размером size байт в
буфер ptr.
fwrite(ptr, size, count, file) — пишет count элементов из буфера ptr в файл.
fgets(str, n, file) — читает строку (до n-1 символов) в массив str.
fputs(str, file) — пишет строку в файл.
29
30. Пример: Форматированная запись
#include <stdio.h>int main() {
FILE* file = fopen("log_c.txt", "w");
if (file) {
const char* message = "Hello from fprintf!";
int number = 42;
// Записываем в файл отформатированную строку.
fprintf ( file, "%s\nNumber: %d\n", message, number );
fclose(file);
}
return 0; }
// Hello from fprintf!
// Number: 42
30
31. Пример: Бинарная запись структуры с fwrite
Пример: Бинарная записьструктуры с fwrite
#include <stdio.h>
struct Person {
char name[50];
int age;
double height;
};
int main() {
Person p = {“Ivan Sidorow", 18, 170.0};
FILE* file = fopen("person_c.dat", "wb"); // "wb" - write binary
if (file) {
size_t elements_written = fwrite( &p, sizeof(Person), 1, file);
if (elements_written != 1) { /* Обработка ошибки записи*/
fclose(file);
}
return 0; }
31
}
32. Позиционирование: fseek и ftell
Позиционирование: fseek и ftellint fseek (FILE* stream, long offset, int origin) — устанавливает указатель
позиции в файле.
позиции: SEEK_SET (начало),
SEEK_CUR (текущая позиция),
SEEK_END (конец).
long ftell ( FILE* stream) — возвращает текущую позицию в файле.
32
33. Пример
FILE* file = fopen("data.bin", "rb");if (file) {
fseek(file, 0, SEEK_END); // Переместиться в конец файла.
long fileSize = ftell (file); // Узнать размер файла.
rewind(file); // Макрос, эквивалентный fseek(file, 0, SEEK_SET); - в начало.
fclose(file);
}
33
34. WinAPI: Мощь и контроль операционной системы
WinAPI (Windows Application Programming Interface) — это обширный наборнизкоуровневых функций, структур и констант, предоставляемых операционной
системой Microsoft Windows для взаимодействия с ее ядром и компонентами.
В отличие от стандартных библиотек C и C++, WinAPI предоставляет прямой,
ничем не опосредованный доступ к функционалу ОС, что дает программисту
беспрецедентный уровень контроля над всеми аспектами работы с системой,
включая файловый ввод-вывод, управление памятью, процессами, потоками и
графическим интерфейсом.
Работа с файлами через WinAPI является фундаментом, на котором
построены все другие, более высокоуровневые методы в среде Windows.
34
35. Базовые концепции: дескрипторы и функции
Дескриптор (HANDLE): Ключевое понятие в WinAPI. Дескриптор — это непросто число, а абстрактная ссылка на внутренний объект ядра Windows (в
данном случае — на открытый файл). После успешного открытия
функция CreateFile возвращает этот дескриптор, который затем необходимо
передавать во все последующие функции (ReadFile, WriteFile, CloseHandle) для
идентификации файла, с которым производится операция.
Тип HANDLE инкапсулирует этот идентификатор, обеспечивая
типобезопасность.
Функции: WinAPI представляет собой именно процедурный интерфейс,
состоящий из множества функций
(например, CreateFileW, ReadFile, SetFilePointer), а не классов с методами.
35
36. Функция CreateFile
Функция CreateFile#include <windows.h> // Главный заголовочный файл для WinAPI
int main() {
// Внимание: Используется широкий символ (wchar_t)
// и префикс L для поддержки Unicode.
HANDLE hFile = CreateFileW( L"C:\\path\\to\\file.txt", // Путь к файлу (Unicode)
GENERIC_READ | GENERIC_WRITE, // Желаемый доступ: чтение и запись
FILE_SHARE_READ,
NULL,
// Режим совместного доступа: другие могут читать
// Атрибуты безопасности (по умолчанию)
OPEN_ALWAYS, // Стратегия создания: открыть, если есть, иначе создать
FILE_ATTRIBUTE_NORMAL,
NULL
);
// Флаги атрибутов файла (обычный файл)
// не используется
36
37. Функция CreateFile
Функция CreateFile// продолжение
if (hFile == INVALID_HANDLE_VALUE) {
// Ошибка! Анализируем код с помощью GetLastError()
DWORD err = GetLastError();
return 1;
}
// Файл успешно открыт, работаем с hFile...
CloseHandle(hFile); // ОБЯЗАТЕЛЬНО закрываем описатель !
return 0;
}
37
38. Параметры CreateFile
Параметры CreateFileПараметры доступа (dwDesiredAccess):
GENERIC_READ: Запрос права на чтение.
GENERIC_WRITE: Запрос права на запись.
Параметры создания (dwCreationDisposition):
CREATE_NEW: Создать новый; ошибка, если существует.
CREATE_ALWAYS: Создать новый; перезаписать существующий.
OPEN_EXISTING: Открыть существующий; ошибка, если не существует.
OPEN_ALWAYS: Открыть существующий; создать, если не существует.
TRUNCATE_EXISTING: Открыть и обнулить длину; ошибка, если не существует.
Флаги и атрибуты (dwFlagsAndAttributes):
FILE_ATTRIBUTE_NORMAL: Самый обычный файл.
FILE_FLAG_SEQUENTIAL_SCAN: Оптимизация для последовательного доступ
38
39. ДЗ 3, pr7
Использовать каждый из трех способов (fstream, fopen, WinAPI) дляработы с файлами:
1. CreateFile – создать новый файл через WinAPI
Если файл уже существует, спросить пользователя о его
перезаписи.
2. Add: через функции с-библиотеки
Добавить новую произвольную запись (предложение) в конец
файла.
Затем еще одну, в начало файла.
Затем третье предложение – снова в конец файла.
Данные вводятся пользователем с клавиатуры через консоль.
3. Read: прочитать файл через fstream
4. Вывести текст на консоль.
Крайний срок присылки: воскресенье
39
40. Контрольная работа 3
Напишите на листке свою фамилию имя и группу.Объясните, какие из следующих строк кода скомпилируются, а какие
— нет, и почему.
int x = 10;
const int y = 20;
int& r1 = x; // 1 : ответ и объяснение
int& r2 = y; // 2 : …
int& r3 = 30; // 3
const int& cr1 = x; // 4
const int& cr2 = y; // 5
const int& cr3 = 40; // 6
40
programming