C++文件读取与字符分割

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]进行进一步的分割,将其中的四个数字提取出来。
分析这一字符串可以发现,[]是我们不需要的,而四个数字以“, ”作为分隔。鉴于此,我们可以这样做:
  1. 首先去除[]的干扰。
  2. 利用", "对字符串进行分割。
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;
}


  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
通过stringstream实现字符串分割的方法如下: 首先,需要包含sstream头文件。然后,可以使用stringstream类来创建一个字符串流对象。可以使用字符串流对象的输入运算符(>>)来读取字符串,将其存储在一个临时变量中。然后,可以将临时变量的值存储在一个容器中,如vector,以便进一步处理。 下面是一个示例代码: ```cpp #include <sstream> #include <vector> #include <string> std::vector<std::string> splitString(const std::string& str, char delimiter) { std::vector<std::string> result; std::stringstream ss(str); std::string item; while (std::getline(ss, item, delimiter)) { result.push_back(item); } return result; } ``` 在这个示例中,我们定义了一个名为splitString的函数,它接受一个字符串和一个分隔符作为参数。函数首先创建一个字符串流对象ss,并将输入的字符串str传递给它。然后,我们使用std::getline函数来从字符串流中按照指定的分隔读取每个部分,并将它们存储在一个临时变量item中。然后,我们将临时变量item添加到结果容器result中。最后,函数返回结果容器result。 这样,我们就可以调用splitString函数来实现文件分割字符串的功能,只需要传入文件读取字符串分隔符即可。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [C++字符串分割方法总结](https://blog.csdn.net/wzxiaodu/article/details/120131403)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值