C/C++ IO操作

项目中碰到一个文件IO的问题,如下:

现有文本文件InputFile.txt,内容大致为:

//==================================================
//POV-Ray Geometry file
//==================================================
//This file has been created by PoseRay v3.13.21.571
//3D model to POV-Ray/Moray Converter.
//Author: FlyerX
//Email: flyerx_2000@yahoo.com
//Web: https://sites.google.com/site/poseray/
//==================================================
 
//Materials
#include "armadillo_POV_mat.inc"
 
//Geometry
#declare armadillo_unnamed_material_=mesh2{
vertex_vectors{
106289,
<2.312181,0.1683176,0.8163048>,
<2.311077,0.1786384,0.8170696>,
<2.308454,0.1687992,0.8194576>,
<2.283935,0.213596,0.821744>,
<2.27917,0.2198224,0.819728>,
<2.278454,0.2137072,0.8223384>,
<2.330702,0.2852856,0.7614728>,
<2.324658,0.2909416,0.7601728>,
<2.326384,0.2866528,0.7637816>,
<2.21661,0.3663198,0.6235906>,
<2.220123,0.3622722,0.6229381>,
<2.217081,0.3619105,0.6271858>,
<2.274469,0.1575984,0.6827952>,
<2.270182,0.1531384,0.6872344>,
<2.27057,0.1579048,0.6830072>,
<2.184279,0.3989262,0.6556019>,
<2.183541,0.3982444,0.657621>,
<2.18146,0.4030383,0.6557837>,
...
<-0.4670421,-0.5036201,-0.7268002>,
<0.6455061,0.7251832,-0.2396481>,
<-0.7230348,0.6187588,-0.3071779>,
<-0.7314488,0.5028389,-0.4605819>
}

face_indices{
212574,
<0,1,2>,
<3,4,5>,
<6,7,8>,
<9,10,11>,
<12,13,14>,
<15,16,17>,
<18,19,20>,
...
<103021,67168,97077>,
<106084,106276,105340>,
<106084,90380,106276>
}

normal_indices{
212574,
<0,1,2>,
<3,4,5>,
<6,7,8>,
...
}
inside_vector <0,0,1> }

//Model assembly from the meshes
#declare armadillo_=
object{armadillo_unnamed_material_  /*material{unnamed_material_}*/ hollow }


需求如下:

实现一个函数,读取该文本文件,从vertex_vectors中提取出其中的106289个顶点的坐标,比如从<2.312181,0.1683176,0.8163048>,中提取出Vector3f(2.312181,0.1683176,0.8163048); 所有的顶点会保存在vector<Vector3f> initial_vertices这样的一个vector中。程序每隔一段时间会计算出一个平移和旋转矩阵,然后根据initial_vertices计算出新值,保存在vector<Vector3f> updated_vertices中,之后新建一个新的文本文件OutputFile.txt,按照InputFile.txt格式输出,只是vertex_vectors中的所有顶点坐标用updated_vertices的值替换。

之前对文件操作和字符串处理不太熟悉,看了下C的IO操作,然后自己简单的实现了下,功能上基本可以满足自己的需求。以下为代码:

#include <vector>
#include <stdio.h>
#include <string.h>

using namespace std;

struct Vector3f
{
	Vector3f(float x1, float x2, float x3)
		:v1(x1), v2(x2), v3(x3)
	{

	}

	float v1;
	float v2;
	float v3;
};
const size_t kMaxNum = 100;	// 字符数组最大容量
char g_buffer[kMaxNum];

void ProcessVertices(const vector<Vector3f>& initial_vertices, vector<Vector3f>& updated_vertices)
{
	const size_t num_vertices = initial_vertices.size();
	for (int i = 0; i < num_vertices; ++i)
	{
		const Vector3f& tmp_vertex = initial_vertices[i];
		Vector3f new_vertex(tmp_vertex.v1 + 10.0f, tmp_vertex.v2 + 10.0, tmp_vertex.v3 + 10.0);
		updated_vertices.push_back(new_vertex);
	}
}

void ExtractVertices( FILE* input_file, FILE* output_file, vector<Vector3f> &initial_vertices, vector<Vector3f>& updated_vertices ) 
{
	// 逐行读取文件,直到读取的字符串含有vertex_vectors子串
	do 
	{
		char* result;
		result = fgets(g_buffer, kMaxNum-1, input_file);
		if (result)
		{
			fputs(g_buffer, output_file);
		}
	} while ((strstr(g_buffer, "vertex_vectors") == NULL));

	// 从下一行读取num_vertices
	Vector3f tmp_vertex(0.0f, 0.0f, 0.0f);
	size_t total_num;
	fgets(g_buffer, kMaxNum-1, input_file);
	sscanf(g_buffer, "%d", &total_num);

	// 接下来读取num_vertices行,并提取顶点坐标用于初始化initial_vertices
	for (int i = 0; i < total_num; ++i)
	{
		fgets(g_buffer, kMaxNum-1, input_file);
		sscanf(g_buffer, "<%f,%f,%f>,", &tmp_vertex.v1, &tmp_vertex.v2, &tmp_vertex.v3);
		initial_vertices.push_back(tmp_vertex);
	}

	// 对顶点做变换
	ProcessVertices(initial_vertices, updated_vertices);

	// 输出更新后的顶点坐标
	sprintf(g_buffer, "%d,\n", total_num);
	fputs(g_buffer, output_file);
	for (int i = 0; i < total_num; ++i)
	{
		const Vector3f& tmp_vertex = updated_vertices[i];
		sprintf(g_buffer, "<%f,%f,%f>,\n", tmp_vertex.v1, tmp_vertex.v2, tmp_vertex.v3);
		fputs(g_buffer, output_file);
	}
}

void ExtractNormals( FILE* input_file, FILE* output_file, vector<Vector3f> &initial_normals, vector<Vector3f>& updated_normals )
{
	// 然后再次逐行读取文件,直到读取的字符串含有normal_vectors子串
	do 
	{
		char* result;
		result = fgets(g_buffer, kMaxNum-1, input_file);
		if (result)
		{
			fputs(g_buffer, output_file);
		}
	} while ((strstr(g_buffer, "normal_vectors") == NULL));

	// 从下一行读取num_normals
	Vector3f tmp_vertex(0.0f, 0.0f, 0.0f);
	size_t total_num;
	fgets(g_buffer, kMaxNum-1, input_file);
	sscanf(g_buffer, "%d", &total_num);

	// 接下来读取num_normals行,并提取法线向量用于初始化initial_normals
	for (int i = 0; i < total_num; ++i)
	{
		fgets(g_buffer, kMaxNum-1, input_file);
		sscanf(g_buffer, "<%f,%f,%f>,", &tmp_vertex.v1, &tmp_vertex.v2, &tmp_vertex.v3);
		initial_normals.push_back(tmp_vertex);
	}	

	// 对法线做变换
	ProcessVertices(initial_normals, updated_normals);

	// 输出更新后的法线向量
	sprintf(g_buffer, "%d,\n", total_num);
	fputs(g_buffer, output_file);
	for (int i = 0; i < total_num; ++i)
	{
		const Vector3f& tmp_vertex = updated_normals[i];
		sprintf(g_buffer, "<%f,%f,%f>,\n", tmp_vertex.v1, tmp_vertex.v2, tmp_vertex.v3);
		fputs(g_buffer, output_file);
	}
}

void ReadRestContents( FILE* input_file, FILE* output_file )
{
	// 读取文件剩余内容
	while(fgets(g_buffer, kMaxNum-1, input_file))
	{
		fputs(g_buffer, output_file);
	}
}

void PovrayGeomFileTransformation_new(const char* input_file_name, const char* output_file_name, vector<Vector3f>& initial_vertices, vector<Vector3f>& updated_vertices, 
									  vector<Vector3f>& initial_normals, vector<Vector3f>& updated_normals)
{
	FILE* input_file;
	FILE* output_file;
	input_file = fopen(input_file_name, "r");
	if (input_file == NULL)
	{
		perror(input_file_name);
		exit(EXIT_FAILURE);
	}
	output_file = fopen(output_file_name, "w+");
	if (output_file == NULL)
	{
		fclose(input_file);
		perror(output_file_name);
		exit(EXIT_FAILURE);
	}

	ExtractVertices(input_file, output_file, initial_vertices, updated_vertices);

	ExtractNormals(input_file, output_file, initial_normals, updated_normals);

	ReadRestContents(input_file, output_file);

	fclose(input_file);
	fclose(output_file);
}

int main(int argc, char* argv[])
{	
	vector<Vector3f> initial_vertices;
	vector<Vector3f> updated_vertices;
	vector<Vector3f> initial_normals;
	vector<Vector3f> updated_normals;

	const char* input_file_name		= "armadillo_POV_geom_backup.inc";
	const char* output_file_name	= "armadillo_POV_geom.inc";

	PovrayGeomFileTransformation_new(input_file_name, output_file_name, initial_vertices, updated_vertices, initial_normals, updated_normals);

	return 0;
}

PS:本来打算用C++的iostream, 看过 C++ 工程实践(7):iostream 的用途与局限 后决定还是用C的IO。


补充:

C语言对字符串数组的处理太麻烦,本文采用C++的string class来简化数据处理

#include <vector>
#include <stdio.h>
#include <string>

using namespace std;

struct Vector3f
{
	Vector3f(float x1, float x2, float x3)
		:v1(x1), v2(x2), v3(x3)
	{

	}

	float v1;
	float v2;
	float v3;
};

typedef vector<Vector3f> RigidBodyGeom;
typedef vector<string>   RigidBodyPovGeomContents;

const int kMaxNum = 100;	
char g_buffer[kMaxNum];

void ReadContextPart( FILE* input_file, vector<string> &context_part, const char* vertices_type)
{
	do 
	{
		char* result;
		result = fgets(g_buffer, kMaxNum, input_file);
		if (result)
		{
			context_part.push_back(string(g_buffer));
		}
	} while ((strstr(g_buffer, vertices_type) == NULL));
}

void ExtractVerticesData( FILE* input_file, vector<Vector3f> &initial_vertices_data )
{
	// First read num_vertices
	int total_num;
	if (fgets(g_buffer, kMaxNum, input_file))
	{
		if (1 != sscanf(g_buffer, "%d", &total_num))		// check if total num has been read correctly
		{
			printf("Error read num_vertices!");
			exit(EXIT_FAILURE);
		}
	}
	else
	{
		printf("Empty line for total_num!");
		exit(EXIT_FAILURE);
	}

	Vector3f tmp_vertex(0.0f, 0.0f, 0.0f);
	// Then read num_vertices rows and extract coordinates for initial_vertices_data initialization 
	for (int i = 0; i < total_num; ++i)
	{
		if (fgets(g_buffer, kMaxNum, input_file))
		{
			if (3 != sscanf(g_buffer, "<%f,%f,%f>,", &tmp_vertex.v1, &tmp_vertex.v2, &tmp_vertex.v3))	// check if all 3 coordinates have been read correctly
			{
				printf("Error read coordinates!");
				exit(EXIT_FAILURE);
			}
			initial_vertices_data.push_back(tmp_vertex);
		}
		else
		{
			printf("Incorrect num_vertices rows!");
			exit(EXIT_FAILURE);
		}
	}
}

void ReadRestContents( FILE* input_file, vector<string> &context_part)
{
	while(fgets(g_buffer, kMaxNum, input_file))
	{
		context_part.push_back(string(g_buffer));
	}
}

void ProcessVertices(const vector<Vector3f>& initial_vertices, vector<Vector3f>& updated_vertices)
{
	const int num_vertices = initial_vertices.size();
	for (int i = 0; i < num_vertices; ++i)
	{
		const Vector3f& tmp_vertex = initial_vertices[i];
		Vector3f new_vertex(tmp_vertex.v1 + 10.0f, tmp_vertex.v2 + 10.0, tmp_vertex.v3 + 10.0);
		updated_vertices.push_back(new_vertex);
	}
}

void WriteContextPart(FILE* output_file, const vector<string> &context_part)
{
	const int total_num = context_part.size();
	for (int i = 0; i < total_num; ++i)
	{
		strcpy(g_buffer, context_part[i].c_str());
		fputs(g_buffer, output_file);
	}
}

void WriteContextVertices(FILE* output_file, const vector<Vector3f> &updated_vertices_data)
{
	const int total_num = updated_vertices_data.size();
	sprintf(g_buffer, "%d,\n", total_num);
	fputs(g_buffer, output_file);
	for (int i = 0; i < total_num; ++i)
	{
		const Vector3f& tmp_vertex = updated_vertices_data[i];
		sprintf(g_buffer, "<%f,%f,%f>,\n", tmp_vertex.v1, tmp_vertex.v2, tmp_vertex.v3);
		fputs(g_buffer, output_file);
	}
}

void ReadInitialPovGeomFile(const char* input_file_name, vector<Vector3f>& initial_vertices, vector<Vector3f>& initial_normals, 
					 vector<string>& context_part1, vector<string>& context_part2, vector<string>& context_part3)
{
	FILE* input_file;
	input_file = fopen(input_file_name, "r");
	if (input_file == NULL)
	{
		perror(input_file_name);
		exit(EXIT_FAILURE);
	}

	// read files line by line until encountering "vertex_vectors"
	const char* kVertexVector = "vertex_vectors";
	ReadContextPart(input_file, context_part1, kVertexVector);

	ExtractVerticesData(input_file, initial_vertices);

	// read files line by line until encountering "vertex_vectors"
	const char* kNormalVector = "normal_vectors";
	ReadContextPart(input_file, context_part2, kNormalVector);

	ExtractVerticesData(input_file, initial_normals);

	ReadRestContents(input_file, context_part3);

	fclose(input_file);
}

void UpdateVerticesData(const vector<Vector3f>& initial_vertices, const vector<Vector3f>& initial_normals, vector<Vector3f> &updated_vertices, vector<Vector3f> &updated_normals)
{
	ProcessVertices(initial_vertices, updated_vertices);

	ProcessVertices(initial_normals, updated_normals);
}

void WriteUpdatedContents(const vector<string> &context_part1, const vector<string> &context_part2, const vector<string> &context_part3,
	const vector<Vector3f>& updated_vertices, const vector<Vector3f>& updated_normals, const char* output_file_name)
{
	FILE* output_file;
	output_file = fopen(output_file_name, "w+");
	if (output_file == NULL)
	{
		perror(output_file_name);
		exit(EXIT_FAILURE);
	}

	WriteContextPart(output_file, context_part1);

	// output updated vertices
	WriteContextVertices(output_file, updated_vertices);

	WriteContextPart(output_file, context_part2);

	// output updated normals
	WriteContextVertices(output_file, updated_normals);

	WriteContextPart(output_file, context_part3);

	fclose(output_file);
}

void ReadAllPovFiles(const vector<string>& input_file_names, vector<RigidBodyGeom>& rigid_body_initial_vertices, vector<RigidBodyGeom>& rigid_body_initial_normals, 
	vector<RigidBodyPovGeomContents>& rigid_body_context_part1, vector<RigidBodyPovGeomContents>& rigid_body_context_part2, vector<RigidBodyPovGeomContents>& rigid_body_context_part3)
{
	const int num_names = input_file_names.size();
	for (int i = 0; i < num_names; ++i)
	{
		vector<Vector3f>	initial_vertices;
		vector<Vector3f>	initial_normals;
		vector<string>		context_part1;
		vector<string>		context_part2;
		vector<string>		context_part3;

		ReadInitialPovGeomFile(input_file_names[i].c_str(), initial_vertices, initial_normals, context_part1, context_part2, context_part3);

		rigid_body_initial_vertices.push_back(initial_vertices);
		rigid_body_initial_normals.push_back(initial_normals);
		rigid_body_context_part1.push_back(context_part1);
		rigid_body_context_part2.push_back(context_part2);
		rigid_body_context_part3.push_back(context_part3);
	}
}

void UpdateAllPovVertices(const vector<RigidBodyGeom>& rigid_body_initial_vertices, const vector<RigidBodyGeom>& rigid_body_initial_normals, 
	vector<RigidBodyGeom>& rigid_body_updated_vertices, vector<RigidBodyGeom>& rigid_body_updated_normals)
{
	const int num_rigid_bodies = rigid_body_initial_vertices.size();
	for (int i = 0; i < num_rigid_bodies; ++i)
	{
		const vector<Vector3f>& initial_vertices = rigid_body_initial_vertices[i];
		const vector<Vector3f>& initial_normals = rigid_body_initial_normals[i];
		vector<Vector3f> updated_vertices;
		vector<Vector3f> updated_normals;
		UpdateVerticesData(initial_vertices, initial_normals, updated_vertices, updated_normals);
		rigid_body_updated_vertices.push_back(updated_vertices);
		rigid_body_updated_normals.push_back(updated_normals);
	}
}

void WriteAllPovFiles(const vector<string>& output_file_names, vector<RigidBodyGeom>& rigid_body_updated_vertices, vector<RigidBodyGeom>& rigid_body_updated_normals, 
	const vector<RigidBodyPovGeomContents>& rigid_body_context_part1, const vector<RigidBodyPovGeomContents>& rigid_body_context_part2, const vector<RigidBodyPovGeomContents>& rigid_body_context_part3)
{
	const int num_rigid_bodies = rigid_body_updated_vertices.size();
	for (int i = 0; i < num_rigid_bodies; ++i)
	{
		const vector<Vector3f>& updated_vertices = rigid_body_updated_vertices[i];
		const vector<Vector3f>& updated_normals = rigid_body_updated_normals[i];
		WriteUpdatedContents(rigid_body_context_part1[i], rigid_body_context_part2[i], rigid_body_context_part3[i], updated_vertices, updated_normals, output_file_names[i].c_str());
	}
}


int main(int argc, char* argv[])
{	
	vector<RigidBodyGeom> rb_initial_vertices;
	vector<RigidBodyGeom> rb_initial_normals;
	vector<RigidBodyGeom> rb_updated_vertices;
	vector<RigidBodyGeom> rb_updated_normals;
	vector<RigidBodyPovGeomContents>  contexts_part1;
	vector<RigidBodyPovGeomContents>  contexts_part2;
	vector<RigidBodyPovGeomContents>  contexts_part3;

	// mark POV files to be processed
	vector<string> input_file_names;
	input_file_names.push_back(string("Computer_POV_geom.inc"));
	input_file_names.push_back(string("CSE_POV_geom.inc"));
	input_file_names.push_back(string("Games_POV_geom.inc"));
	input_file_names.push_back(string("International_POV_geom.inc"));
	input_file_names.push_back(string("islandSCI1_POV_geom.inc"));
	input_file_names.push_back(string("Journal_POV_geom.inc"));
	input_file_names.push_back(string("R_POV_geom.inc"));
	input_file_names.push_back(string("science_POV_geom.inc"));
	input_file_names.push_back(string("Technology_POV_geom.inc"));
	input_file_names.push_back(string("venus_POV_geom.inc"));

	// determine output file names
	string base_name, extension_name;
	vector<string> output_file_names;	
	const int num_names = input_file_names.size();
	for (int i = 0; i < num_names; ++i)
	{
		// search period in file name
		string& file_name = input_file_names[i];
		string::size_type idx = file_name.find('.');
		if (idx == string::npos)
		{
			// file name does not contain any period
			printf("File name error!");
			exit(EXIT_FAILURE);
		}
		else
		{
			// split file name into base name and extension name
			base_name = file_name.substr(0, idx);
			extension_name = file_name.substr(idx+1);
			output_file_names.push_back(base_name + string("0001") + "." + extension_name);
		}
	}

	ReadAllPovFiles(input_file_names, rb_initial_vertices, rb_initial_normals, contexts_part1, contexts_part2, contexts_part3);

	UpdateAllPovVertices(rb_initial_vertices, rb_initial_normals, rb_updated_vertices, rb_updated_normals);

	WriteAllPovFiles(output_file_names, rb_updated_vertices, rb_updated_normals, contexts_part1, contexts_part2, contexts_part3);

	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值