1 简单文本读取
对于简单文本,即文本在文件中没有特殊格式不需要进行解析,只需要简单的读取或写入文本中的每一行数据,可以通过C++中#include<fstream>
提供的接口进行实现
1.1 C++方式的文件读写
C++提供了关于文件读写操作的接口#include<fstream>
,其中ofstream类
可以用于文件的写入,ifstream类
可以用于文本的读取
对应c语言中"w"、“w+”等标识符。无论向文本中写入内容还是从文本中读取内容,可以通过在open函数中添加各种标识符作为参数,以不同的方式打开文件。
在进行文本操作时,以下方式是能够进行组合使用的,以“或”运算(“|”)的方式。
ios::in //为输入(读)而打开文件
ios::out //为输出(写)而打开文件
ios::ate //初始位置:文件尾
ios::app //所有输出附加在文件末尾
ios::trunc //如果文件已存在则先删除该文件
ios::binary //二进制方式
1.1.1 文本简单写入
#include<iostream>
#include<fstream>//定义了用于处理输入输出的类
#include<string>
using namespace std;
int main()
{
string fileName = "./txtTest.txt";
ofstream fout;
//1.创建和打开文本文件
//fout.open(fileName.c_str(), ios::out);//以文件写入的方式打开,若文件不存在则创建文件,若存在清空文件内容并重新写入
fout.open(fileName.c_str(), ios::out | ios::app);//以文件写入并追加的方式打开,若文件不存在则创建文件
//2.判断文件是否打开成功
if (fout.is_open())
{
std::cout << "Creat and open file sucess!" << endl;
}//if
//3.向文件中写入文本
for(int i=0;i<5;i++)
{
fout<<i<<" Hello word!"<<endl;
}
cout<<"Write file sucess!"<<endl;
//4.关闭打开的文件
fout.close();
return 0;
}
1.1.2 文本简单读取
#include<iostream>
#include<fstream>//定义了用于处理文本输入与输出的类
#include<sstream>//定义了流的输入输出类
#include<string>
using namespace std;
int main()
{
string fileName = "./txtTest.txt";
ifstream fin;
//打开文本文件
fin.open(fileName.c_str(), ios::in);
//判断文本文件是否成功打开
if (!fin.is_open())
{
cout << "Open file failed!" << endl;
exit(EXIT_FAILURE);//若打开失败则中断程序
}
else
cout << "Open file sucess!" << endl;
while (!fin.eof())//判断读取是否到达文件末尾
{
string str_txt;
getline(fin,str_txt);//将一整行数据作为一个字符串读入
if (!str_txt.empty())//判断该行数据是否读入成功
{
cout << str_txt << endl;
//当文本的某一行既包含字符串又包含数字,或者包含多个类别的文本元素时,
//如果想一次读取一行文本,并对该行的每一个元素分别处理可以使用stringstream类
stringstream ss;
ss << str_txt;
int index;
string message;
ss >> index >> message;
cout << index << "\t" << message << endl;
}
}
fin.close();
system("pause");
return 0;
}
1.1.3 工程应用的一点思考
在工程应用中,有时文本文件可能用来存储程序运行过程中产生的一些Log文件,亦或是我们想要保存的一些数据,这种情况通过1.1.1
和1.1.2
中即可实现
但有时也会将文本作为参数文件,格式如下。这时可以结合string和map的一些操作,实现参数读取和查找某个固定参数的功能。
# students info
name=lsx
age=16
classes=9
grade=A
#include "stdafx.h"
#include<iostream>
#include<fstream>//定义了用于处理文本输入与输出的类
#include<sstream>//定义了流的输入输出类
#include<string>
#include<map>
using namespace std;
//参数读取类
class Params {
public:
//构造函数
Params()
{
//初始化文件名称
string fileName = "param_config";
ifstream fin;
//打开文本文件
fin.open(fileName.c_str(), ios::in);
//判断文本文件是否成功打开
if (!fin.is_open())
{
cout << "Open file failed!" << endl;
exit(EXIT_FAILURE);//若打开失败则中断程序
}
else
cout << "Open file sucess!" << endl;
while (!fin.eof())//判断读取是否到达文件末尾
{
string str_txt;
getline(fin, str_txt);//将一整行数据作为一个字符串读入
if (!str_txt.empty())//判断该行数据是否为空
{
if (str_txt[0] == '#')//如果该行是以#开始,则是注释行,跳过
continue;
int pos = str_txt.find("=");//如果该行的数据格式不对则跳过
if (pos == -1)
continue;
string key = str_txt.substr(0, pos);
string value = str_txt.substr(pos + 1, str_txt.length());
config_data[key] = value;
}
if (!fin.good())
break;
}
fin.close();
}
//析构函数
~Params()
{
map<string, string> map_empty;
config_data.swap(map_empty);
config_data.clear();
}
//查找key对应的value
string getParamData(string key)
{
map<string, string>::iterator it = config_data.find(key);
if (it == config_data.end())
{
cerr << "Parameter name " << key << " not found!" << endl;
return string("NOT_FOUND");
}
return it->second;
}
public:
map<string,string> config_data;
};
int main()
{
Params pa;
string name = pa.getParamData("name");
string age = pa.getParamData("age");
string classes = pa.getParamData("classes");
string grade = pa.getParamData("grade");
cout << "student info:" << endl;
cout << "\tname=" << name << endl;
cout << "\tage=" << age << endl;
cout << "\tclasses=" << classes << endl;
cout << "\tgrade=" << grade << endl;
system("pause");
return 0;
}
2 csv文件读取
和上述简单文本读取操作相同,只不过在写入和读取文本时,CSV每一行中的每一个表格之间需要用逗号,
隔开
如果不用逗号,
隔开,那么输入的内容会被融合在一个表格中
#include "stdafx.h"
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
using namespace std;
int main()
{
string FileName = "./data.csv";
//写文件
ofstream fout;
fout.open(FileName.c_str(),ios::out);
if (!fout.is_open())
{
cout << "open or create file failed." << endl;
exit(EXIT_FAILURE);
}
for (int i = 0; i < 5; i++)
fout << 12 << "," << 13 << "," << 14 << "," << "Nan" << endl;
fout.close();
// 读文件
ifstream inFile("./data.csv", ios::in);
string lineStr;
while (getline(inFile, lineStr))
{
stringstream ss(lineStr);
string c1, c2, c3, c4, c5;
ss >> c1 >> c2 >> c3 >> c4 >> c5;
cout << c1 << c2 << c3 << c4 << c5 << endl;
}
system("pause");
return 0;
}
3 ini文件读取
找了半天没有找到一种比较好的方式解析ini配置文件,自己写一个简单的api吧
其实看ini配置文件的格式和txt类型的配置文件差不多,只不过他将所有的信息划分为若干个节Section
那感觉这样可以通过ofstream
和ifstream
类提供的方法进行文件读写。
稍微不同的是,这里把每一个Section
作为独立的一个map,然后把这个map放入一个更大的map中
但是这样做似乎有些粗糙,代码设计上不够优美;另外这里使用无序容器unordered_map替代map,因为map是一个支持自动排序的容器,每当插入一对新的键值对都会调用一次排序算法,这里我们换成unordered_map减少计算时间
这里只稍作演示,不考虑等号左右存在空格的情况
ini文件格式
# 个人信息
[info]
name=lsx
age=16
school=beijingUS
classes=9
# 体检信息
[health]
high=178
weight=65.3
# 成绩信息
[grade]
Chinese=120
English=132
Math=100
示例代码
#include "stdafx.h"
#include<iostream>
#include<fstream>//定义了用于处理文本输入与输出的类
#include<sstream>//定义了流的输入输出类
#include<string>
#include<map>
#include<unordered_map>//无序容器
using namespace std;
class Params {
public:
//构造函数
Params()
{
//初始化文件名称
string fileName = "param.ini";
ifstream fin;
//打开文本文件
fin.open(fileName.c_str(), ios::in);
//判断文本文件是否成功打开
if (!fin.is_open())
{
cout << "Open file failed!" << endl;
exit(EXIT_FAILURE);//若打开失败则中断程序
}
else
cout << "Open file sucess!" << endl;
string section_name;
while (!fin.eof())//判断读取是否到达文件末尾
{
string str_txt;
getline(fin, str_txt);//将一整行数据作为一个字符串读入
if (!str_txt.empty())//判断该行数据是否为空
{
if (str_txt[0] == '#')//如果该行是以#开始,则是注释行,跳过
continue;
//获取节的名称
if (str_txt[0] == '[')
{
section_name = str_txt.substr(1,str_txt.length()-2);
unordered_map<string, string> sub_map;
data[section_name] = sub_map;
continue;
}
else
{
int pos = str_txt.find("=");//如果该行的数据格式不对则跳过
if (pos == -1)
continue;
string key = str_txt.substr(0, pos);
string value = str_txt.substr(pos + 1, str_txt.length());
data[section_name][key] = value;
}
}
if (!fin.good())
break;
}
fin.close();
}
//析构函数
~Params()
{
unordered_map<string, unordered_map<string,string> > map_empty;
data.swap(map_empty);
data.clear();
}
//根据section和key的值,查找指定的value
string getParamData(string section, string key)
{
//查找节section对应的map
unordered_map<string, unordered_map<string, string> >::iterator it_total = data.find(section);
if (it_total == data.end())
{
cerr << "Parameter section " << section << " not found!" << endl;
return string("Section NOT_FOUND");
}
//查找具体的key对应的value
unordered_map<string, string>::iterator it = data[section].find(key);
if (it == data[section].end())
{
cerr << "Parameter name " << key << " not found!" << endl;
return string("NOT_FOUND");
}
return it->second;
}
public:
//map<string, map<string,string> > data;
unordered_map<string, unordered_map<string, string> > data;
};
int main()
{
Params pa;
string name = pa.getParamData("info","name");
cout << "[info]name = " << name << endl;
system("pause");
return 0;
}