1. 概述
C++标准库提供了 头文件中的几个类来进行文件操作,这些类封装了底层的文件操作,提供了面向对象和类型安全的接口,使得文件读写更加便捷和高效。主要的文件流类包括:
std::ifstream
:用于从文件中读取数据。
std::ofstream
:用于向文件中写入数据。
std::fstream
:用于同时读取和写入文件。
这些文件流类(
std::ifstream
、
std::ofstream
、
std::fstream
)继承自
std::istream
、
std::ostream
和
std::iostream
,这些类本身继承自
std::ios
,从而提供了丰富的成员函数和操作符来处理文件I/O。
2. 文件流类详解
2.1 std::ifstream:输入文件流
std::ifstream
用于从文件中读取数据。它继承自
std::istream
,具备所有输入流的功能,同时添加了文件特有的操作。
#include<fstream>#include<iostream>#include<string>intmain(){// 创建并打开输入文件流
std::ifstream infile("input.txt");// "input.txt" 是要读取的文件名// 检查文件是否成功打开if(!infile){
std::cerr <<"无法打开文件 input.txt"<< std::endl;return1;}// 读取并输出文件内容
std::string line;while(std::getline(infile, line)){
std::cout << line << std::endl;}// 关闭文件流(可选,因为析构函数会自动关闭)
infile.close();return0;}要点:
构造函数可以在创建对象时指定文件名和打开模式。
检查文件是否成功打开,以避免后续操作错误。
使用
std::getline逐行读取文件内容。
2.2 std::ofstream:输出文件流
std::ofstream
用于向文件中写入数据。它继承自
std::ostream
,具备所有输出流的功能,同时添加了文件特有的操作。
#include<fstream>#include<iostream>#include<string>intmain(){// 创建并打开输出文件流
std::ofstream outfile("output.txt");// "output.txt" 是要写入的文件名// 检查文件是否成功打开if(!outfile){
std::cerr <<"无法打开文件 output.txt"<< std::endl;return1;}// 写入数据到文件
outfile <<"Hello, World!"<< std::endl;
outfile <<"这是第二行文本。"<< std::endl;// 关闭文件流(可选,因为析构函数会自动关闭)
outfile.close();return0;}要点:
默认情况下,
std::ofstream以写入模式打开文件。如果文件不存在,会创建新文件;如果文件存在,会截断文件内容。使用
<<操作符向文件中插入数据。
2.3 std::fstream:文件流(读写)
std::fstream
用于同时读取和写入文件。它继承自
std::iostream
,结合了
std::istream
和 std::ostream 的功能
#include<fstream>#include<iostream>#include<string>intmain(){// 创建并打开文件流,设置为读写模式
std::fstream file("file.txt", std::ios::in | std::ios::out | std::ios::app);// 检查文件是否成功打开if(!file){
std::cerr <<"无法打开文件 file.txt"<< std::endl;return1;}// 写入数据到文件
file <<"追加一行内容。"<< std::endl;// 移动读指针到文件开头
file.seekg(0, std::ios::beg);// 读取并输出文件内容
std::string line;while(std::getline(file, line)){
std::cout << line << std::endl;}// 关闭文件流
file.close();return0;}要点:
通过构造函数的第二个参数指定文件打开模式,可以组合多个模式。
适用于需要同时进行读取和写入操作的场景。
3. 打开和关闭文件
文件流类提供了多种方式来打开和关闭文件。
可以在创建文件流对象时,通过构造函数直接指定文件名和打开模式。
std::ifstream infile("input.txt");// 以默认模式(即只读方式)打开 input.txt
std::ofstream outfile("output.txt", std::ios::out | std::ios::trunc);// 以写入和截断模式打开 output.txt
如果在创建对象时没有指定文件名,可以使用
open()
成员函数在后续打开文件。
#include<fstream>#include<iostream>intmain(){
std::ifstream infile;// 创建输入文件流对象
infile.open("input.txt");// 打开文件if(!infile.is_open()){
std::cerr <<"无法打开文件 input.txt"<< std::endl;return1;}// 进行读取操作...
infile.close();// 关闭文件return0;}
使用
close()
成员函数可以显式关闭文件流。尽管在对象销毁时,析构函数会自动关闭文件,但在需要提前释放资源时,显式调用
close()
是必要的。
infile.close();
outfile.close();4. 文件打开模式
文件打开模式通过
std::ios::openmode
枚举类型指定,可以组合使用多个模式。
常用的打开模式:
-
std::ios::in
:以读取模式打开文件。
std::ios::out:以写入模式打开文件。std::ios::app:以追加模式打开文件,写入操作将添加到文件末尾。std::ios::ate:打开文件后,将文件指针定位到文件末尾。std::ios::trunc:如果文件已存在,则截断文件长度为0(默认与 std::ofstream 相关)。std::ios::binary:以二进制模式打开文件。
// 以读写模式打开文件,不截断现有内容
std::fstream file("data.txt", std::ios::in | std::ios::out);// 以二进制模式写入数据, 截断现有文件内容
std::ofstream binaryOut("data.bin", std::ios::out | std::ios::binary | std::ios::trunc);说明:
组合使用:通过按位或操作符 | 组合多个打开模式,如
std::ios::in | std::ios::out表示同时具备读取和写入权限。二进制模式:对于非文本文件(如图片、音频等),应使用
std::ios::binary模式,以防止数据在读取或写入过程中被转换。
5. 读取文件
5.1 使用 >> 操作符读取单词
>>
操作符用于从文件中提取数据,自动跳过空白字符(如空格、换行符、制表符)。
假设 words.txt 文件内容如下:
#include<fstream>#include<iostream>#include<string>intmain(){
std::ifstream infile("words.txt");if(!infile){
std::cerr <<"无法打开文件 words.txt"<< std::endl;return1;}
std::string word;while(infile >> word){// 逐词读取
std::cout <<"读取到的单词: "<< word << std::endl;}
infile.close();return0;}
输出如下:
适用于逐词读取数据,适合处理由空白字符分隔的数据。
无法读取包含空格的完整句子或短语。
5.2 使用 std::getline 逐行读取
std::getline 函数用于从文件中逐行读取数据,适用于处理文本文件中的行数据。
假设 lines.txt 文件内容如下:
#include<fstream>#include<iostream>#include<string>intmain(){
std::ifstream infile("lines.txt");if(!infile){
std::cerr <<"无法打开文件 lines.txt"<< std::endl;return1;}
std::string line;while(std::getline(infile, line)){// 逐行读取
std::cout <<"读取到的行: "<< line << std::endl;}
infile.close();return0;}
输出如下:
适用于逐行处理文件内容,保留每行的完整信息。
可以处理包含空格和其他特殊字符的行。
5.3 读取整个文件内容
有时需要一次性读取整个文件内容,尤其适用于小文件或需要对整个文件内容进行处理的场景。
假设 content.txt 文件内容如下:
#include<fstream>#include<iostream>#include<string>intmain(){
std::ifstream infile("content.txt");if(!infile){
std::cerr <<"无法打开文件 content.txt"<< std::endl;return1;}// 使用迭代器读取整个文件内容到字符串
std::string content((std::istreambuf_iterator<char>(infile)),
std::istreambuf_iterator<char>());
std::cout <<"文件内容:\n"<< content << std::endl;
infile.close();return0;}
输出如下:
使用
std::istreambuf_iterator
迭代器可以高效地读取整个文件内容。
适用于小至中等大小的文件,对于非常大的文件,可能需要分块读取以避免内存问题。
对此行代码的理解:
std::string content((std::istreambuf_iterator<char>(infile)),
std::istreambuf_iterator<char>());这行代码使用了
std::istreambuf_iterator来从输入文件流infile读取内容并构建一个std::string对象。具体理解如下:std::istreambuf_iterator(infile):创建一个输入迭代器,从 infile 的缓冲区读取字符。std::istreambuf_iterator():这是一个空的迭代器,用于表示输入结束。
构造std::string:通过传入两个迭代器,构造函数会从infile中读取所有字符,直到遇到结束迭代器。最终,这行代码的作用是将整个文件的内容读入到
content字符串中。这样,你就可以方便地对文件内容进行操作。
5.4 读取二进制数据
对于非文本文件(如图片、音频、视频等),需要以二进制模式读取数据,以防止数据在读取过程中被转换或丢失。
假设需要读取一个图片文件 image.jpg 并输出其大小。
#include<fstream>#include<iostream>#include<vector>intmain(){// 以二进制模式打开文件
std::ifstream infile("image.jpg", std::ios::binary);if(!infile){
std::cerr <<"无法打开文件 image.jpg"<< std::endl;return1;}// 移动读指针到文件末尾以获取文件大小//这行代码将文件指针移动到文件的末尾。seekg 函数用于设置输入流的位置,0 是偏移量
infile.seekg(0, std::ios::end);//tellg 函数返回当前文件指针的位置(即文件的长度)
std::streamsize size = infile.tellg();//这行代码将文件指针重置回文件的开头
infile.seekg(0, std::ios::beg);// 读取文件内容到缓冲区
std::vector<char>buffer(size);if(infile.read(buffer.data(), size)){
std::cout <<"成功读取 "<< size <<" 字节。"<< std::endl;}else{
std::cerr <<"读取文件失败!"<< std::endl;}
infile.close();return0;}
输出如下:
说明:
使用
std::ios::binary模式打开文件,确保数据按原样读取。通过
seekg和tellg获取文件大小,预分配缓冲区。使用
read函数读取二进制数据到缓冲区。
6. 写入文件
6.1 使用 << 操作符写入数据
<<
操作符用于向文件中插入数据,类似于向标准输出流 std::cout 中插入数据。
将用户信息写入文件 users.txt。
#include<fstream>#include<iostream>#include<string>intmain(){
std::ofstream outfile("users.txt");if(!outfile){
std::cerr <<"无法打开文件 users.txt"<< std::endl;return1;}// 写入用户信息
outfile <<"用户名: Alice\n年龄: 30\n"<< std::endl;
outfile <<"用户名: Bob\n年龄: 25\n"<< std::endl;
outfile <<"用户名: Charlie\n年龄: 35\n"<< std::endl;
outfile.close();
std::cout <<"用户信息已写入 users.txt"<< std::endl;return0;}
输出如下:
文件即自动创建于当前工程根目录下
说明:
使用
<<操作符可以方便地将各种数据类型写入文件。std::endl用于插入换行符并刷新缓冲区。
6.2 使用 std::ofstream::write 写入二进制数据
对于需要写入二进制数据的场景,使用 write() 成员函数更为合适。
将一个字符数组写入二进制文件 output.bin。
#include<fstream>#include<iostream>#include<vector>intmain(){
std::ofstream outfile("output.bin", std::ios::binary | std::ios::trunc);if(!outfile){
std::cerr <<"无法打开文件 output.bin"<< std::endl;return1;}// 准备二进制数据
std::vector<char> data ={'H','e','l','l','o','\0'};// 写入二进制数据到文件
outfile.write(data.data(), data.size());if(!outfile){
std::cerr <<"写入文件失败!"<< std::endl;}else{
std::cout <<"成功写入 "<< data.size()<<" 字节到 output.bin"<< std::endl;}
outfile.close();return0;}
data.data()
:获取 data 字符串的指针,指向字符串的首字符。这是写入的起始地址。
data.size()
:返回字符串 data 的长度,表示要写入的字节数。
outfile.write(data.data(), data.size());
:调用 write 函数,将从 data 指针开始的
data.size()
字节写入 outfile 中。
输出如下:
说明:
使用
write()可以指定要写入的数据地址和字节数,适用于二进制数据。确保文件以二进制模式打开,防止数据被意外转换。
7. 一个实际使用的示例
读取mysql中conf文件的配置:
boolConnectionPool::loadConfigFile(){//setenv("MYSQL_CONF_PATH","/home/kyros1ee/QtEnviroment/WeChat-main/chatserver/conf/mysql.conf",1);// 设置环境变量或绝对路径constchar* configPath =getenv("MYSQL_CONF");//if(!configPath){
LOG_ERROR <<" mysql.conf MYSQL_CONF_PATH not set!";returnfalse;}
ifstream file(configPath);if(!file.is_open()){
LOG_ERROR <<"mysql.conf 文件不存在!";returnfalse;}
string line;while(getline(file, line)){// 忽略空行和注释行if(line.empty()|| line.find('=')== string::npos)continue;if(line.back()=='\r'){
line.pop_back();}
istringstream iss(line);
string key, value;if(getline(iss, key,'=')&&getline(iss, value)){// 去除可能存在的前后空白
key =trim(key);
value =trim(value);if(key =="ip") _ip = value;elseif(key =="port") _port =stoi(value);elseif(key =="username") _username = value;elseif(key =="password") _password = value;elseif(key =="dbname") _dbname = value;elseif(key =="initSize") _initSize =stoi(value);elseif(key =="maxSize") _maxSize =stoi(value);elseif(key =="maxIdleTime") _maxIdleTime =stoi(value);elseif(key =="connectionTime") _connectionTimeout =stoi(value);}}returntrue;}

发布评论