【C++学习】数据读入-格式2(多列)
掌握多列数据读入方法后,可通过改写代码从txt文件批量读入二维数据。
1. 功能概述
1.1 功能效果
需要读入多个二维数据表,但文件数据可能格式不对齐,或者存在非法字符、缺少数据,读入程序要具备数据检查功能。
1.2 使用方法
- 输入要求:每个表都有相同的维度,并且共用两个自变量x和y;
- 读入结果:有两种使用方法,看需。
#include "Map2DArray.h"//std,map,iostream,fstream
int main()
{
map<string, double**> mapMath;
Map2DArray Math(".\\math.txt", mapMath);
int nHeader = Math.getNHeader();
int rowInt = Math.getRowInt();
int colInt = Math.getColInt();
double *xInt = Math.getXInt();
double *yInt = Math.getYInt();
/* 使用方法1 */
cout << "使用方法1:" << endl;
for (int iHeader = 0; iHeader < 1; iHeader++) {
cout << "f1(x,y)" << "\t";
for (int i = 0; i < colInt; i++) {
cout << yInt[i] << "\t";
}
cout << endl;
for (int i = iHeader * rowInt; i < (iHeader + 1)*rowInt; i++) {
cout << xInt[i - iHeader * rowInt] << "\t";
for (int j = 0; j < colInt; j++) {
cout << mapMath["f1(x,y)"][i][j] << "\t";
}
cout << endl;
}
cout << "f2(x,y)" << "\t";
for (int i = 0; i < colInt; i++) {
cout << yInt[i] << "\t";
}
cout << endl;
for (int i = iHeader * rowInt; i < (iHeader + 1)*rowInt; i++) {
cout << xInt[i - iHeader * rowInt] << "\t";
for (int j = 0; j < colInt; j++) {
cout << mapMath["f2(x,y)"][i][j] << "\t";
}
cout << endl;
}
}
/* 使用方法2 */
cout << "使用方法2:" << endl;
Math.Disp();
return 0;
}
2. 注意事项
- 如果文件中的数据存在科学计数法,只要将’E’或’e’加入判断即可,但我几乎没遇到这种类型;
- 也许有人想用多个具有不同维度的表,这会给数据检查带来困难,我一般把不同维度的表放在不同文件。
3. 详细代码
Map2DArray.h
/*
* Auther: sanfan66
*
* Date | Change
*--------------------------------------------
* 230926 | <record>: None→Version 0.0a,Original finished
* | (describe): Map2DArray needs input-file with a header in front of the data
* | (describe): '\t'or' 'to separate the words
* | !warning!: ~Map2DArray may not called in some cases
*/
#pragma once
#include <fstream>//ifstream
#include <map>
#include <iostream>//cout
#include <string>//getline
#define EPS 1e-7
using namespace std;//map,string,ifstream
class Map2DArray {
public:
Map2DArray(const char *path, map<string, double**>&map_name);
~Map2DArray();
int getNum(ifstream *file, const char *path);
double getData(ifstream *file, const char *path);
int getNHeader() const { return nHeader; };
int getRowInt() const { return rowInt; };
int getColInt() const { return colInt; };
double *getXInt() const { return xInt; };
double *getYInt() const { return yInt; };
int isMathNumb(char MathNumb) const {
return ((MathNumb - '0' > -EPS && MathNumb - '9' < EPS) || MathNumb == '.' || MathNumb == '-' || MathNumb == '+');
}
void Disp() const;
private:
int nHeader;
int rowData;
int colData;
int rowInt;
int colInt;
double *xInt ;
double *yInt ;
char **header_name;
double **lines_data;
};
Map2DArray.cpp
#include "Map2DArray.h"
Map2DArray::Map2DArray(const char *path, map<string, double**>&map_name) {
/* 打开文件、读入行数、读取数据、赋值地址 */
ifstream file;
file.open(path, ios::in);
if (!file.is_open()) {
cout << path << "无法打开" << endl;
system("Pause");
exit(0);
}
getNum(&file, path);
xInt = new double[rowInt];
yInt = new double[colInt];
header_name = new char*[nHeader];
for (int i = 0; i < nHeader; i++) {
header_name[i] = new char[100];
}
lines_data = new double*[nHeader*rowInt];
for (int i = 0; i < nHeader*rowInt; i++) {
lines_data[i] = new double[colInt];
}
getData(&file, path);
for (int i = 0; i < nHeader; i++) {
map_name[header_name[i]] = &lines_data[i*rowInt];//!!lines_data[i*rowInt]是数据的地址,不是**
}
file.close();
}
Map2DArray::~Map2DArray() {
/* 清理堆空间,new对应delete,new[]对应delete[] */
delete[] xInt;
xInt = nullptr;
delete[] yInt;
yInt = nullptr;
for (int i = 0; i < nHeader; i++) {
delete[] header_name[i];
header_name[i] = nullptr;
}
delete[] header_name;
header_name = nullptr;
for (int i = 0; i < nHeader*rowInt; i++) {
delete[] lines_data[i];
lines_data[i] = nullptr;
}
delete[] lines_data;
lines_data = nullptr;
}
int Map2DArray::getNum(ifstream *file, const char *path) {
/* 获取行数 */
int indexHeader = 0;
int indexRow = 0;
int indexLines = 0;
string one_line;
while (file->peek() != EOF) {
getline(*file, one_line);
int indexCol = 0;//统计每行的列数
char *buf = &one_line[0];
char *one_line_char = nullptr;
char *next_word_ptr = buf;
while (*next_word_ptr != '\0') { //取一行,每次以制表符或空格分隔取出一个词
one_line_char = strtok_s(buf, "\t ", &next_word_ptr);
if (one_line_char != nullptr) { //连续的分隔符会返回空指针
int isNumber = 0;
for (unsigned i = 0; i < strlen(one_line_char); i++) {
if (isMathNumb(one_line_char[i])) {
isNumber++;
}
}
if (isNumber == strlen(one_line_char)) {//是数字
if (indexCol == 0) {
indexRow++;
}
}
else {//是非数字字符
if (indexCol == 0) {
indexHeader++;
}
else {
cout << path << "第" << indexLines + 1 << "行第" << indexCol + 1 << "个词有非数字字符(不包括表头)" << endl;
system("Pause");
exit(0);
}
}
indexCol++;
}
buf = nullptr;
}
if (indexHeader == 1) {//使用第一行数据判断列数
colData = indexCol;
}
else {
if (indexCol > 0 && colData != indexCol) { //跳过只有回车/空格的行
cout << path << "第" << indexLines + 1 << "行数据个数=" << indexCol << ",而列数=" << colData << endl;
system("Pause");
exit(0);
}
}
indexLines++;
}
if (indexHeader == 0) {
cout << path << "没有表头" << endl;
system("Pause");
exit(0);
}
rowData = indexRow;
nHeader = indexHeader;
if (rowData% nHeader) {// %整数取余,/结果保留整数部分,同(int)
cout << path << "数据列数/表头个数=" << rowData / nHeader << "余" << rowData % nHeader << endl;
system("Pause");
exit(0);
}
else {
rowInt = rowData / nHeader;
colInt = colData - 1;
}
return 0;
}
double Map2DArray::getData(ifstream *file, const char *path) {
/* 读取数据 */
file->clear();
file->seekg(0, ios::beg);
int indexHeader = 0;
int indexRow = 0;
int indexUsefulLines = 0;//只统计有效的行
string one_line;
while (file->peek() != EOF) {
getline(*file, one_line);
int indexCol = 0;//统计每行的列数
char *buf = &one_line[0];
char *one_line_char = nullptr;
char *next_word_ptr = buf;
while (*next_word_ptr != '\0') { //取一行,每次以制表符或空格分隔取出一个词
one_line_char = strtok_s(buf, "\t ", &next_word_ptr);
if (one_line_char != nullptr) { //连续的分隔符会返回空指针
/* 读表头和数据 */
if (indexUsefulLines % (rowInt + 1) != 0) {
if (indexCol == 0) {
if (indexRow < rowInt) {
xInt[indexRow] = atof(one_line_char);//读第一个表的自变量x
}
}
else {
lines_data[indexRow][indexCol - 1] = atof(one_line_char);//读入二维数据
if (indexCol == colInt) {//找到一行的最后一个数
indexRow++;
}
}
}
else {
if (indexCol == 0) {
strcpy_s(header_name[indexHeader], strlen(one_line_char) + 1, one_line_char);//读入表头
indexHeader++;
}
else {
if (indexUsefulLines == 0) {
yInt[indexCol - 1] = atof(one_line_char);//读第一个表的自变量y
}
}
}
indexCol++;
}
buf = nullptr;
}
if (indexCol != 0) {
indexUsefulLines++;
}
}
return 0;
}
/* 使用方法2 */
void Map2DArray::Disp() const {
for (int iHeader = 0; iHeader < nHeader; iHeader++) {
cout << header_name[iHeader] << "\t";
for (int i = 0; i < colInt; i++) {
cout << yInt[i] << "\t";
}
cout << endl;
for (int i = iHeader * rowInt; i < (iHeader + 1)*rowInt; i++) {
cout << xInt[i - iHeader * rowInt] << "\t";
for (int j = 0; j < colInt; j++) {
cout << lines_data[i][j] << "\t";
}
cout << endl;
}
}
return;
}