使用流操作的方法实现
在进行开发的过程中,有时候光通过终端看输出的数据比较费劲,无法事后进行对比分析等操作。所以需要将数据写入文档中,方便后续使用。
实现步骤:
1. 首先需要包含头文件#include <fstream>
2. 声明类用于读取、写入数据
ofstream //文件写操作 内存写入存储设备
ifstream //文件读操作,存储设备读取到内存中
fstream //读写操作,对打开的文件可进行读写操作
在这两个对象中,ofstream::open或ifstream::open是打开文件的函数,该函数默认以out或in的方式读入或写出,这两种方式都会先清空文件中的数据,如果想在上一次执行该操作的文件后加入数据,那么就要用ios类中的app方法,ios:app(后面有具体的不同指令含义的介绍)
ios::app:打开文件不会清空数据,文件指针始终在文件尾,因此只能在文件尾写数据。
利用这一点就可以实现添加数据到文件尾的方法
打开文件的方式在ios类(所以流式I/O的基类)中定义,有如下几种方式:
指令 | 作用 |
---|---|
ios::in | 为输入(读)而打开文件 |
ios::out | 为输出(写)而打开文件 |
ios::out | 为输出(写)而打开文件 |
ios::ate | 初始位置:文件尾 |
ios::app | 所有输出附加在文件末尾 |
ios::trunc | 如果文件已存在则先删除该文件 |
ios::binary | 二进制方式 |
这些方式是能够进行组合使用的,以“或”运算(“|”)的方式:例如
ofstream out;
out.open("Hello.txt", ios::in|ios::out|ios::binary) //根据自己需要进行适当的选取
举例:下面这个代码是我在开发ros程序时候用的
#include <fstream>
#include <iostream>
# define class_num 20
void depth_callback(const darknet_ros_msgs::BoundingBoxes::ConstPtr& detect_msg, const sensor_msgs::Image::ConstPtr& msg)
{
int u[class_num] = {};
int v[class_num] = {};
int centerIdx[class_num] = {};
int temp1[class_num] ={};
int temp2[class_num] ={};
int temp3;
int sizes = msg->data.size();
float* depths = (float*)(&msg->data[0]);
int num = detect_msg->bounding_boxes.size();
// 看一下视频的宽度
temp3 = msg->width;
for (int i = 0; i < num; i++)
{
// 看一下输出的数据是否为负数
temp1[i] = (detect_msg->bounding_boxes[i].xmax - detect_msg->bounding_boxes[i].xmin)/2;
temp2[i] = (detect_msg->bounding_boxes[i].ymax - detect_msg->bounding_boxes[i].ymin)/2;
u[i] = ((detect_msg->bounding_boxes[i].xmax - detect_msg->bounding_boxes[i].xmin)/2) + detect_msg->bounding_boxes[i].xmin;
v[i] = ((detect_msg->bounding_boxes[i].ymax - detect_msg->bounding_boxes[i].ymin)/2) + detect_msg->bounding_boxes[i].ymin;
centerIdx[i] = u[i] + msg->width * v[i];
if (centerIdx[i] < 0)
{
centerIdx[i] = 0;
}
else if (centerIdx[i] > sizes /4)
{
centerIdx[i] = sizes /4;
}
}
std::cout<<"Bouding Boxes (header):" << detect_msg->header <<std::endl;
std::cout<<"Bouding Boxes (image_header):" << detect_msg->image_header <<std::endl;
std::cout<<"Bouding Boxes (Class):" << "\t";
std::ofstream write;
write.open("result-test.csv", std::ios::app);
for (int i = 0; i < num; i++)
{
std::cout << detect_msg->bounding_boxes[i].Class << "\t";
std::cout<<"Center distance : " << depths[centerIdx[i]] << " m" << std::endl;
std::cout<<"temp1 : " << i << ": " << temp1[i] << std::endl;
std::cout<<"temp2 : " << i << ": " << temp2[i] << std::endl;
std::cout<<"temp3 : " << temp3 << std::endl;
write << i << ","<<"中心点位置" <<","<< centerIdx[i] << ","<< "temp1"<<","<<temp1[i]<<"," <<"temp2"<<","<<temp2[i]<<","<<"temp3"<<","<< temp3<<","<<"x"<<","<<u[i]<<","<<"y"<<","<<v[i]<< std::endl;
}
write.close();
std::cout << "\033[2J\033[1;1H"; // clear terminal
}
输出结果如下:
-------------------------------------------------------------更新:2020.08.05-------------------------------------------------------------
新增操作,每次执行前先清空这个文档的方法
本文开始讲的方法可以完成在循环执行的程序中实现在末尾添加新的内容,但是如果这个程序执行了两遍,那么这个文档中的数据就是两次运行得到数据的总和。如果我们想每次运行这个程序的时候都是得到一个新的数据,并且还不想更改这个csv文件的名字,那么可以在程序中添加一个初始化的操作。
在执行回调函数的开始先执行下面这段代码即可完成上述功能。
// 在进入回调函数的时候添加这段代码
ofstream clearfile; //每次打开的时候先将文件内容清空
clearfile.open("result-test.csv", ios::out | ios::trunc );
clearfile.close();
这段代码实际上就是用了ios::trunc的功能:如果文件已存在则先删除该文件,这样就可以在每次执行程序的时候都是一个新的文件。并且名字还是原来的名字。