C++文件的读取以及字符的分割是在工程中常用到的操作。这段时间正好又接触到了这些,就顺便记录一下。
C:\Users\Administrator\Desktop\liuwei
1500.jpg 1 [192, 132, 213, 205]
1501.jpg 1 [183, 136, 201, 212]
1502.jpg 1 [161, 149, 186, 233]
第一行是文件的根目录,第二行开始是文件名、人数、以及每个人的坐标。
目的是为了将文件的根目录存储下来(也就是第一行),然后将之后的文字按属性存储。下面按照步骤来完成这一要求。
一、文件的读取
在C/C++的文件读取形式有很多种。如果环境允许,我认为使用ifstream最为方便。使用ifstream需要包含头文件"fstream"。具体的代码如下:
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
ifstream fs("1.txt");
if (!fs.is_open())
{
cout << "Error in open file!" << endl;
return -1;
}
char buff[256];
while (!fs.eof())
{
fs.getline(buff, 256); //读取文件中的一行
/***Do Somethings**/
//
//
//
/******************/
}
return 0;
}
二、字符串分割
字符串分割是C语言常用的技巧之一,尽管在学习C语言的时候我们也经常练习字符串的分割技巧。对于初学者来说,字符串的分割确实让人头疼。想要正确的分割出字符串,需要分析字符串的结构组成。在上面的例子,从文件第二行来看,我们需要分割的字符串是这样的:
1500.jpg 1 [192, 132, 213, 205]
- 1500.jpg //图片名
- 1 //行人个数
- [192, 132, 213, 205] //BoundingBox的坐标
这三段字符都以制表符分隔开(制表符的ASCII码是9)。所以我们第一步是将这三段字符串分割开。
1. 使用strtok函数进行分割
使用strtok函数可以很好的对字符串进行分隔。相关代码如下:
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
ifstream fs("1.txt");
if (!fs.is_open())
{
cout << "Error in open file!" << endl;
return -1;
}
char buff[256];
char RootPath[256];
int index = 1;
while (!fs.eof())
{
fs.getline(buff, 256); //读取文件中的一行
if (index == 1) //第一行是文件根目录
{
memcpy(RootPath, buff, sizeof(buff));
cout << "root path is " << RootPath << endl;
index++;
}
else
{
char* p;
char ImgName[256];
/************ImgPath************/
char ImgPath[256];
p = strtok(buff, " "); //以制表符为分隔,分隔出第一个字符串,即1500.jpg
string ImgName_str = p;
ImgName_str.erase(ImgName_str.size() - 4, ImgName_str.size()); //删除文件名后的.jpg。只保留1500
sprintf(ImgName, "%s", ImgName_str.data());
sprintf(ImgPath, "%s\\%s", RootPath, p);
cout << "ImgPath: " << ImgPath << endl;
/*************PersonNum********/
p = strtok(NULL, " "); //以制表符为分隔,分隔出第二个字符串,即1
int PersonNum = atoi(p); //将字符1转换成数字
cout << "PersonNum: "<<PersonNum<<endl;
/*************Point************/
for (int i = 0; i<PersonNum; i++)
{
int pt[4]; //存储BoundingBox的坐标
p = strtok(NULL, " "); //以制表符为分隔,分隔出字符串[192, 132, 213, 205]
}
index++;
}
}
return 0;
}
2. 使用string::find()和string::substr()进行分割
对得到的字符串[192, 132, 213, 205]进行进一步的分割,将其中的四个数字提取出来。
分析这一字符串可以发现,[]是我们不需要的,而四个数字以“, ”作为分隔。鉴于此,我们可以这样做:
- 首先去除[]的干扰。
- 利用", "对字符串进行分割。
string::find()能够找到相应分隔符在字符串中的位置(index),而string::substr()能够根据index和length截取字符串。利用这两个函数,我们可以对上面的字符串进行分割。
注:为了使分割更加的方便,我们常常使用string::erase来消除已分割出来的字符串。也可以不对原字符串进行消除操作,但是需要计算好分割字符串的位置信息。
我们为了方便计算,每次分割字符串后使用erase()消除掉不必要的字符串信息。
下面是分割这一字符串的相关代码:
/*************Point************/
for (int i = 0; i<PersonNum; i++)
{
int pt[4]; //存储BoundingBox的坐标
p = strtok(NULL, " "); //以制表符为分隔,分隔出字符串[192, 132, 213, 205]
string str = p;
str.erase(0, 1); //消除[
for (int j = 0; j<4; j++)
{
int pos = str.find(", "); //寻找,的位置
string point = str.substr(0, pos); //提取数字字符串
pt[j] = atoi(point.data()); //将提取出来的字符串转换成数字
str.erase(0, pos + 2); //消除已经分隔的字符串,方便后续操作的分割
}
}
至此,所有的字符串都已经分割出来。下面来个整合版。
三、读取文件,并分割字符串
还是上面的例子。这次将上面的两种方法都用上,完整版的代码如下:
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
ifstream fs("1.txt");
if (!fs.is_open())
{
cout << "Error in open file!" << endl;
return -1;
}
char buff[256];
char RootPath[256];
int index = 1;
while (!fs.eof())
{
fs.getline(buff, 256); //读取文件中的一行
/**do somethings**/
//
//
//
/******************/
if (index == 1)
{
memcpy(RootPath, buff, sizeof(buff));
cout << "root path is " << RootPath << endl;
index++;
}
else
{
//fs.getline(buff,256);
char* p;
char ImgName[256];
/************ImgPath************/
char ImgPath[256];
p = strtok(buff, " ");
string ImgName_str = p;
ImgName_str.erase(ImgName_str.size() - 4, ImgName_str.size());
sprintf(ImgName, "%s", ImgName_str.data());
sprintf(ImgPath, "%s\\%s", RootPath, p);
cout << "ImgPath: " << ImgPath << endl;
/*************PersonNum********/
p = strtok(NULL, " ");
int PersonNum = atoi(p);
//cout << "PersonNum: "<<PersonNum<<endl;
/*************Point************/
for (int i = 0; i<PersonNum; i++)
{
int pt[4];
p = strtok(NULL, " ");
//num1
string str = p;
str.erase(0, 1);
for (int j = 0; j<4; j++)
{
int pos = str.find(", ");
string point = str.substr(0, pos);
pt[j] = atoi(point.data());
str.erase(0, pos + 2);
}
//计算roi位置
int start_x, start_y;
int height, width;
start_x = pt[0];
start_y = pt[1];
height = pt[3] - pt[1];
width = pt[2] - pt[0];
char savePath[256];
sprintf(savePath, "Images/person_%s_%d.jpg", ImgName, i + 1);
/*
//保存图像
Mat Img = imread(ImgPath);
Rect rect(start_x, start_y, width, height);
Mat roi = Img(rect);
IplImage* saveImg = new IplImage(roi);
cvSaveImage(savePath, saveImg);
*/
}
index++;
}
}
return 0;
}