Базовые файловые операции
Начнем с основных файловых операций, выполняемых при помощи fstream:
#include <fstream>
#include <iostream>
#include <string>
int main() {
// Запись в файл
std::ofstream outFile("example.txt");
if (outFile.is_open()) {
outFile << "Hello, World!\n";
outFile << "This is a test file.\n";
outFile.close();
} else {
std::cerr << "Error opening file for writing!" << std::endl;
return 1;
}
// Считывание файла
std::ifstream inFile("example.txt");
std::string line;
if (inFile.is_open()) {
while (std::getline(inFile, line)) {
std::cout << line << std::endl;
}
inFile.close();
} else {
std::cerr << "Error opening file for reading!" << std::endl;
return 1;
}
return 0;
}
Считывание и запись двоичных данных
Вот как обрабатываются двоичные данные:
#include <fstream>
#include <iostream>
struct Person {
char name[50];
int age;
double salary;
};
void writeBinaryFile() {
Person person = {"John Doe", 30, 75000.50};
std::ofstream file("data.bin", std::ios::binary);
if (file.is_open()) {
file.write(reinterpret_cast<char*>(&person), sizeof(Person));
file.close();
}
}
void readBinaryFile() {
Person person;
std::ifstream file("data.bin", std::ios::binary);
if (file.is_open()) {
file.read(reinterpret_cast<char*>(&person), sizeof(Person));
file.close();
std::cout << "Name: " << person.name << std::endl;
std::cout << "Age: " << person.age << std::endl;
std::cout << "Salary: " << person.salary << std::endl;
}
}
int main() {
writeBinaryFile();
readBinaryFile();
return 0;
}
Позиция файла и поиск
И контролируется позиция файлового указателя:
#include <fstream>
#include <iostream>
#include <string>
class FileManager {
private:
std::fstream file;
public:
FileManager(const std::string& filename) {
file.open(filename, std::ios::in | std::ios::out | std::ios::binary);
}
~FileManager() {
if (file.is_open()) {
file.close();
}
}
void seekAndRead(std::streampos position) {
if (file.is_open()) {
file.seekg(position);
char buffer[100];
file.read(buffer, 99);
buffer[99] = '#include <fstream>';
#include <iostream>
#include <string>
class FileManager {
private:
std::fstream file;
public:
FileManager(const std::string& filename) {
file.open(filename, std::ios::in | std::ios::out | std::ios::binary);
}
~FileManager() {
if (file.is_open()) {
file.close();
}
}
void seekAndRead(std::streampos position) {
if (file.is_open()) {
file.seekg(position);
char buffer[100];
file.read(buffer, 99);
buffer[99] = '\0';
std::cout << "Read from position " << position << ": "
<< buffer << std::endl;
}
}
void seekAndWrite(std::streampos position, const std::string& text) {
if (file.is_open()) {
file.seekp(position);
file << text;
file.flush();
}
}
};
int main() {
// Создается тестовый файл
{
std::ofstream outFile("seek_test.txt");
outFile << "This is a test file for seeking operations.\n";
}
FileManager fm("seek_test.txt");
fm.seekAndRead(10); // Считывается из позиции «10»
fm.seekAndWrite(5, "was"); // «is» заменяется на «was»
return 0;
}
std::cout << "Read from position " << position << ": "
<< buffer << std::endl;
}
}
void seekAndWrite(std::streampos position, const std::string& text) {
if (file.is_open()) {
file.seekp(position);
file << text;
file.flush();
}
}
};
int main() {
// Создается тестовый файл
{
std::ofstream outFile("seek_test.txt");
outFile << "This is a test file for seeking operations.\n";
}
FileManager fm("seek_test.txt");
fm.seekAndRead(10); // Считывается из позиции «10»
fm.seekAndWrite(5, "was"); // «is» заменяется на «was»
return 0;
}
Обработка ошибок и состояния файлов
Для файловых операций важна корректная обработка ошибок:
#include <fstream>
#include <iostream>
#include <string>
class FileHandler {
public:
static bool copyFile(const std::string& source, const std::string& dest) {
std::ifstream src(source, std::ios::binary);
if (!src.is_open()) {
std::cerr << "Error opening source file: " << source << std::endl;
return false;
}
std::ofstream dst(dest, std::ios::binary);
if (!dst.is_open()) {
std::cerr << "Error opening destination file: " << dest << std::endl;
src.close();
return false;
}
dst << src.rdbuf();
if (src.fail() || dst.fail()) {
std::cerr << "Error during file copy" << std::endl;
src.close();
dst.close();
return false;
}
src.close();
dst.close();
return true;
}
static void checkFileState(std::fstream& file) {
if (file.good()) {
std::cout << "File stream is good" << std::endl;
}
if (file.eof()) {
std::cout << "End of file reached" << std::endl;
}
if (file.fail()) {
std::cout << "A recoverable error occurred" << std::endl;
}
if (file.bad()) {
std::cout << "A non-recoverable error occurred" << std::endl;
}
}
};
Реальный сценарий: синтаксический анализатор CSV
Вот практический пример парсинга CSV-файлов:
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
class CSVParser {
private:
std::string filename;
char delimiter;
public:
CSVParser(const std::string& fname, char delim = ',')
: filename(fname), delimiter(delim) {}
std::vector<std::vector<std::string>> parse() {
std::vector<std::vector<std::string>> data;
std::ifstream file(filename);
if (!file.is_open()) {
throw std::runtime_error("Could not open file: " + filename);
}
std::string line;
while (std::getline(file, line)) {
std::vector<std::string> row;
std::stringstream ss(line);
std::string cell;
while (std::getline(ss, cell, delimiter)) {
// Удаляются начальный и конечный пробелы
cell.erase(0, cell.find_first_not_of(" \t"));
cell.erase(cell.find_last_not_of(" \t") + 1);
row.push_back(cell);
}
data.push_back(row);
}
file.close();
return data;
}
};
int main() {
try {
CSVParser parser("data.csv");
auto data = parser.parse();
// Выводятся проанализированные данные
for (const auto& row : data) {
for (const auto& cell : row) {
std::cout << cell << "\t";
}
std::cout << std::endl;
}
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
Управление лог-файлами
Вот простая система логирования с fstream:
#include <fstream>
#include <iostream>
#include <string>
#include <ctime>
#include <iomanip>
class Logger {
private:
std::ofstream logFile;
std::string currentTimestamp() {
auto now = std::time(nullptr);
auto tm = *std::localtime(&now);
std::ostringstream oss;
oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
return oss.str();
}
public:
enum Level {
INFO,
WARNING,
ERROR
};
Logger(const std::string& filename) {
logFile.open(filename, std::ios::app);
if (!logFile.is_open()) {
throw std::runtime_error("Could not open log file: " + filename);
}
}
~Logger() {
if (logFile.is_open()) {
logFile.close();
}
}
void log(Level level, const std::string& message) {
if (!logFile.is_open()) return;
std::string levelStr;
switch (level) {
case INFO: levelStr = "INFO"; break;
case WARNING: levelStr = "WARNING"; break;
case ERROR: levelStr = "ERROR"; break;
}
logFile << "[" << currentTimestamp() << "] "
<< std::setw(7) << std::left << levelStr << " : "
<< message << std::endl;
}
};
int main() {
try {
Logger logger("app.log");
logger.log(Logger::INFO, "Application started");
logger.log(Logger::WARNING, "Low memory warning");
logger.log(Logger::ERROR, "Failed to connect to database");
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
Заключение
Благодаря fstream на C++ имеются полноценные возможности обработки файлов. Обобщим ключевые моменты:
- Всегда проверяйте, открыты ли файлы.
- Закончив работу с файлами, закрывайте их.
- Используйте соответствующие файловые режимы: двоичный или текстовый.
- Корректно обрабатывайте ошибки.
- Для управления файлами используйте принципы RAII.
Типичные сценарии:
- Обработка конфигурационных файлов.
- Хранение и выборка данных.
- Управление логами.
- Обработка CSV- и текстовых файлов.
- Операции с двоичными файлами.
Читайте также:
- C++: полное руководство по memset
- Возможности C++, о которых должен знать каждый разработчик
- C++: подробный разбор count_if
Читайте нас в Telegram, VK и Дзен
Перевод статьи ryan: C++ File Handling with fstream: A Complete Guide




