如何高效地CC++编程读取地震切片数据?

2026-05-05 23:351阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计4722个文字,预计阅读时间需要19分钟。

如何高效地C/C++编程读取地震切片数据?

SliceData IO 文档将介绍文本文档的读写,包括文本格式和文件的读写。常见文本资源主要有:层位(.txt)、切片(.txt)、测井(.las、.txt)、断层(.txt)等。这些资源实质上为表格(Table),由表头和数据组构成。

SliceData IO

本文档将介绍文本格式文件的读写,常见的文本资料主要有:

层位(.txt) 切片(.txt) 测井(.las.txt) 断层(.txt)等。这些资料实质上均为表格(Table),由表头和数据组成。

本次练习将对切片(Slice)文件进行读写操作,常见的切片数据样例如下:

Index Line CDP X Y Time(ms) Value 1 4386 2874 409455 4252075 4129.04 -0.7874 1 4386 2875 409455 4252087 4136.59 -1.2206 ... ... ... ... 9 5177 1708 429230 4237500 3273.81 1.1847 9 5177 1709 429230 4237513 3275.52 1.5910

新建头文件SliceDataIO.h与C++文件SliceDataIO.cpp,以及主函数main.cpp

1 编写头文件SliceData.h 1.1 程序描述、调用、声明、定义

/********************************************************************** * Copyright(C) 2018,Company All Rights Reserved * * @file : SliceData.cpp * * @brief : 实现文本数据的读、写操作 * * @version : 1.0 * * @author : Fan XinRan * * @date : 2022/2/8 星期二 * * Others : **********************************************************************/ #pragma once #include<stdio.h> //C Language header file #include<stdlib.h> #include<string.h> #include<math.h> #include<iostream> // C++ header file #include<vector> #include<algorithm> #include"alloc.h" // 用于创建多维数组 #define PI 3.141592654 #define EPS 0.000001 using namespace std; 1.2 定义类

描述了一种数据类型的全部属性(包括可使用它执行的操作),对象是根据这些描述创建的实体。

class Classname { // class + 类名 public: // 公有成员 在程序中类的外部是可访问的,可以不使用任何成员函数来设置和获取公有变量的值 float x; private: // 私有成员 私有成员变量或函数在类的外部是不可访问的,甚至不可查看的 float _y; protected: // 受保护成员 与私有成员相似,不同之处为,受保护成员在子类中是可访问的 float z; } (1) 私有成员

通常情况下都会设置类成员状态为私有(private),以保证良好的封装性。私有成员中的变量和函数一般以(_)开头。

class SliceDataIO{ // 定义一个名为SliceDataIO的类 private: // 私有成员 int *_sliceIndex; // 1 切片号 int *_lineIndex; // 2 线号 int *_cdpIndex; // 3 道号 float *_Xcordinate; // 4 X坐标 float *_Ycordinate; // 5 Y坐标 float *_time; // 6 时间 float *_value; // 7 属性值 int _nsample; // 采样点数 public: // 公有成员 ... }; (2) 公有成员

由于隐藏数据是OOP(面向对象编程)的主要目标之一,因此数据项通常放在私有部分。公有成员函数是程序和对象的私有成员之间的桥梁,通过设计公有成员函数以获取隐藏的数据。

class SliceDataIO{ private: ... public: // 公有成员 SliceDataIO(); // 默认构造函数 没有参数,将创建SliceDataIO类对象,但不初始化其成员 SliceDataIO(int nsample); // 创建一个具有nsample个采样点的类对象 ~SliceDataIO(); // 析构函数 // 获取数据get() int *getSliceIndex(); // 1 声明成员函数:获取切片号 int *getLineIndex(); // 2 ... int *getCDPIndex(); // 3 ... float *getX(); // 4 ... float *getY(); // 5 ... float *getTime(); // 6 ... float *getValue(); // 7 获取属性值 int getSampleNum(); // 声明成员函数:获取采样点数 // 设定数据set() bool setData(vector<int> IndexVector,vector<float> XVector,vector<float> YVector,vector<int> LineVector,vector<int> CDPVector,vector<float> ValueVector,vector<float> TimeVector); }

  1. 构造函数:

    • 是类的一种特殊的成员函数,它会在每次创建类的新对象时执行;
    • 构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。
    • 默认构造函数没有任何参数,带参数的构造函数则会在创建对象时为其赋初始值。
  2. 析构函数:

    • 是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行;
    • 析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数;
    • 析构函数完成清理工作,在跳出程序(比如关闭文件、释放内存等)前释放资源。
  3. vector(向量):是一个能够存放任意类型的动态数组,可在末尾附加新数据,或在中间插入新数据。

1.3 声明函数

声明读、写函数,其中读函数由SliceDataIO类实现。

SliceDataIO *readSliceData(const char *filenameInput); // read slice data from Inputfile bool writeSliceData(const char *filenameOutput, SliceDataIO *slicedata) // write slice data to Outputfile 完整代码

#pragma once #include<stdio.h> //C Language header file #include<stdlib.h> #include<string.h> #include<math.h> #include<iostream> //C++ header file #include<vector> #include<algorithm> #include"alloc.h" #define PI 3.141592654 // 定义全局常量 #define EPS 0.000001 using namespace std; // 声明命名空间 class SliceDataIO{ // 定义一个名为SliceDataIO的类,用于切片数据的读写 public: // 公有成员 SliceDataIO(); SliceDataIO(int nsample); ~SliceDataIO(); // 获取隐藏数据 int *getSliceIndex(); int *getLineIndex(); int *getCDPIndex(); float *getX(); float *getY(); float *getTime(); float *getValue(); int getSampleNum(); // 设定数据 bool setData(vector<int> IndexVector,vector<float> XVector,vector<float> YVector,vector<int> LineVector,vector<int> CDPVector,vector<float> ValueVector,vector<float> TimeVector); private: // 私有成员 // 声明私有变量,包括切片号、线号、道号等 int *_sliceIndex; int *_lineIndex; int *_cdpIndex; float *_Xcordinate; float *_Ycordinate; float *_time; float *_value; int _nsample; }; // 声明读、写函数 SliceDataIO *readSliceData(const char *filenameInput); bool writeSliceData(const char *filenameOutput, SliceDataIO *slicedata); 2 编写C++文件SliceData.cpp 2.1 定义类成员函数

类成员函数是类的一个成员,它可以操作类的任意对象,也可以访问对象中的所有成员。成员函数可以定义在类定义内部,或者单独使用作用域解析运算符(::)来定义,此时(::)前须加类名以标识函数所属的类。

如何高效地C/C++编程读取地震切片数据?

(1)构造函数

// 默认构造函数 SliceDataIO::SliceDataIO(){ // 默认构造函数,将成员初始化为NULL或0 this->_sliceIndex = NULL; // 1 初始化切片号 this->_lineIndex = NULL; // 2 初始化线号 this->_cdpIndex = NULL; // 3 初始化道号 this->_Xcordinate = NULL; // 4 初始化X坐标 this->_Ycordinate = NULL; // 5 初始化Y坐标 this->_time = NULL; // 6 初始化时间值 this->_value = NULL; // 7 初始化属性值 this->_nsample = 0; // 初始化采样点数 }

// 带参数的构造函数 SliceDataIO::SliceDataIO(int nsample){ // 创建一个具有nsample个采样点的类对象,并为其成员分配内存 this->_nsample = nsample; // 输入采样点数nsample,根据采样点数分配内存 this->_sliceIndex = (int*)calloc(this->_nsample, sizeof(int)); this->_lineIndex = (int*)calloc(this->_nsample,sizeof(int)); this->_cdpIndex= (int*)calloc(this->_nsample, sizeof(int)); this->_Xcordinate= (float*)calloc(this->_nsample, sizeof(float)); this->_Ycordinate = (float*)calloc(this->_nsample, sizeof(float)); this->_time = (float*)calloc(this->_nsample,sizeof(float)); this->_value= (float*)calloc(this->_nsample, sizeof(float)); } (2)析构函数

// 析构函数 SliceDataIO::~SliceDataIO(){ // 析构函数完成清理工作 if(this->_cdpIndex!=NULL){ free(this->_cdpIndex); // 释放内存 this->_cdpIndex = NULL; // 成员置空 } if(this->_lineIndex!=NULL){ free(this->_lineIndex); this->_lineIndex = NULL; } if(this->_sliceIndex!=NULL){ free(this->_sliceIndex); this->_sliceIndex = NULL; } if(this->_Xcordinate!=NULL){ free(this->_Xcordinate); this->_Xcordinate = NULL; } if(this->_Ycordinate!=NULL){ free(this->_Ycordinate); this->_Ycordinate = NULL; } if(this->_time!=NULL){ free(this->_time); this->_time = NULL; } if(this->_value!=NULL){ free(this->_value); this->_value = NULL; } }

  1. this:
    • 它是一种特殊的指针,每一个对象都能通过 this 指针来访问自己的地址;
    • this 指针是所有成员函数的隐含参数,因此,在成员函数内部,它可以用来指向调用对象;
    • 只有成员函数才有 this 指针。
  2. ->:称为箭头运算符。在调用类成员时,使用点运算符(.)或箭头运算符(->),点运算符应用于实际的对象;箭头运算符与一个指向对象的指针一起使用。
(3)get()方法函数

首先是get方法,用于获取数据;

int* SliceDataIO::getSliceIndex(){ //定义SliceDataIO的类成员函数getSliceIndex以获取切片号 return this->_sliceIndex; } int*SliceDataIO::getLineIndex(){ return this->_lineIndex; } int* SliceDataIO::getCDPIndex(){ return this->_cdpIndex; } float*SliceDataIO::getX(){ return this->_Xcordinate; } float*SliceDataIO::getY(){ return this->_Ycordinate; } float*SliceDataIO::getTime() { return this->_time; } float*SliceDataIO::getValue() { return this->_value; } int SliceDataIO::getSampleNum(){ return this->_nsample; } (4)set()方法函数

然后是set方法,用于指定数据为当前类对象的值。

bool SliceDataIO::setData(vector<int> IndexVector, vector<float> XVector, vector<float> YVector, vector<int> LineVector, vector<int> CDPVector, vector<float> ValueVector, vector<float> TimeVector){ // 函数接收若干个向量,并将向量值赋给当前的类对象 for(int isample=0; isample < this->_nsample;isample++){ this->_sliceIndex[isample] = IndexVector[isample]; this->_lineIndex[isample] = LineVector[isample]; this->_cdpIndex[isample] = CDPVector[isample]; this->_Xcordinate[isample] = XVector[isample]; this->_Ycordinate[isample] = YVector[isample]; this->_value[isample] = ValueVector[isample]; this->_time[isample] = TimeVector[isample]; } return true; } 2.2 定义读取函数

SliceDataIO *readSliceData(const char *filenameInput){ // 定义读取Slice数据的函数 int Index_temp = 0; // 创建待处理的切片参数,并按类型分别初始化。用于临时存放单一采样点数据 int CDP_temp = 0; int LINE_temp = 0; float X_temp = 0.0f; float Y_temp = 0.0f; float Time_temp = 0.0f; float Value_temp = 0.0f; bool flag = true; // 判断程序是否正常运行 int k = 0; // 当前循环次数 int n1 = 1; // 判定输入是否正常 int nPoint = 0; // 向量(vector)中存放的样本点数 vector<int> IndexVector; // 分别创建vector用于存放切片号、道号、线号等信息 vector<int> LineVector; vector<int> CDPVector; vector<float> XVector; vector<float> YVector; vector<float> TimeVector; vector<float> ValueVector; FILE *fp_input = NULL; // 创建输入指针 fp_input = fopen(filenameInput, "rt"); // 以"rt"方式,即读取文本的方式打开文件 if(fp_input==NULL){ // 非空判定 printf("Can not open %s file!!!\n", filenameInput); return NULL; } fscanf(fp_input,"%*[^\n]%*c"); // " "内为固定正则表达,用于忽略********************************* while(flag == true){ // 当程序正常运行时 n1 = fscanf(fp_input,"%d %d %d %f %f %f %f", &Index_temp,&LINE_temp,&CDP_temp,&X_temp,&Y_temp,&Time_temp,&Value_temp); // 从输入流中分别获取需要的数据 if(n1<0){ flag = false; // 如果读取异常,循环中止 }else{ IndexVector.push_back(Index_temp); LineVector.push_back(LINE_temp); CDPVector.push_back(CDP_temp); XVector.push_back(X_temp); YVector.push_back(Y_temp); TimeVector.push_back(Time_temp); ValueVector.push_back(Value_temp); // 读取正常,追加新数据到向量中 k = k + 1; }//end if(n1<0) if(k%1000==0){ // 每1000轮显示一次进度 printf(" Read numTrace=%d\n",k); }//end if(k%1000==0) }//end while(flag == true) nPoint = ValueVector.size(); // 获取vector中存放的数据条数 SliceDataIO *data = new SliceDataIO(nPoint); // 分配内存 // 为新建的空白对象data设定值,类似粘贴 data->setData(IndexVector, XVector, YVector, LineVector, CDPVector, ValueVector, TimeVector); vector<int>().swap(IndexVector); // 每个向量与空向量交换,即将存有数据的向量置空 vector<int>().swap(LineVector); vector<int>().swap(CDPVector); vector<float>().swap(XVector); vector<float>().swap(YVector); vector<float>().swap(TimeVector); vector<float>().swap(ValueVector); fclose(fp_input); // 关闭输入文件指针 return data; // 返回数据data }

  1. fscanf()从流 stream 读取格式化输入;

    int fscanf(FILE *stream, const char *format, ...)

    • stream-- 指向FILE对象的指针;

    • format-- 这是 C 字符串,包含了以下各项中的一个或多个:空格字符、非空格字符和 format 说明符;

      format说明符形式为 [=%[*][width][modifiers]type=]

  2. new:为任意的数据类型动态分配内存;用法有以下两种:

    • Type *p = new Type;其中,Type 是任意类型名,p 是类型为 Type 的指针;
    • Type *p =new Type[N];用来动态分配一个任意大小的数组,N 代表元素个数;

    malloc() 函数相比,new 的主要的优点是,其不只分配了内存,还创建了对象。

2.3 定义写入函数

bool writeSliceData(const char *filenameOutput, SliceDataIO *slicedata){ int nsample = slicedata->getSampleNum(); // 从类对象slicedata中get各类数据 int *Index = slicedata->getSliceIndex(); int *LineIndex = slicedata->getLineIndex(); int *CdpIndex = slicedata->getCDPIndex(); float *X = slicedata->getX(); float *Y = slicedata->getY(); float *Time = slicedata->getTime(); float *Value = slicedata->getValue(); FILE *fp_output = fopen(filenameOutput,"wt"); //以写入文本的方式打开Outputfile fprintf(fp_output,"Index Line CDP X Y Time(ms) Value\n"); // 先写入表头 for (int isample=0; isample<nsample; isample++){ //遍历类对象中每一个采样点样本 fprintf(fp_output,"%d %d %d %f %f %f %f\n", Index[isample], LineIndex[isample], CdpIndex[isample],X[isample],Y[isample],Time[isample],Value[isample]); //写入到输出流中 if (isample % 1000 == 0) { // 同样,每迭代1000次打印一次进度 printf(" Write numTrace=%d\n", isample); }//end if(k%1000==0) } fclose(fp_output); // 关闭输出文件指针 return true; }

fprintf:发送格式化输出到流 stream 中,用法与fscanf相似;

int fprintf(FILE *stream, const char *format, ...)

  • stream-- 指向FILE对象的指针;

  • format-- 包含了要被写入到流stream中的文本。由以下各项中的一个或多个组成:空格字符、非空格字符和format说明符;

    format说明符形式为 [=%[*][width][modifiers]type=]

完整代码

/***************************************************************************** Function: SliceDataIO Description: read and write slice data Input: const char *filenameInput [in] input filename (.txt) Output: const char *filenameOutput[out] output filename (.txt) Return: bool true program success bool false program failed Author: Fan XinRan Date : 2022/2/8 Others: *****************************************************************************/ #include "SliceDataIO.h" //构造函数 SliceDataIO::SliceDataIO(){ this->_cdpIndex = NULL; this->_lineIndex = NULL; this->_sliceIndex = NULL; this->_Xcordinate = NULL; this->_Ycordinate = NULL; this->_time = NULL; this->_value = NULL; this->_nsample = 0; } //带参数nsample的构造函数 SliceDataIO::SliceDataIO(int nsample){ this->_nsample = nsample; this->_sliceIndex = (int*)calloc(this->_nsample, sizeof(int)); this->_lineIndex = (int*)calloc(this->_nsample,sizeof(int)); this->_cdpIndex= (int*)calloc(this->_nsample, sizeof(int)); this->_Xcordinate= (float*)calloc(this->_nsample, sizeof(float)); this->_Ycordinate = (float*)calloc(this->_nsample, sizeof(float)); this->_time = (float*)calloc(this->_nsample,sizeof(float)); this->_value= (float*)calloc(this->_nsample, sizeof(float)); } //析构函数 SliceDataIO::~SliceDataIO(){ if(this->_cdpIndex!=NULL){ free(this->_cdpIndex); this->_cdpIndex = NULL; } if(this->_lineIndex!=NULL){ free(this->_lineIndex); this->_lineIndex = NULL; } if(this->_sliceIndex!=NULL){ free(this->_sliceIndex); this->_sliceIndex = NULL; } if(this->_Xcordinate!=NULL){ free(this->_Xcordinate); this->_Xcordinate = NULL; } if(this->_Ycordinate!=NULL){ free(this->_Ycordinate); this->_Ycordinate = NULL; } if(this->_time!=NULL){ free(this->_time); this->_time = NULL; } if(this->_value!=NULL){ free(this->_value); this->_value = NULL; } } //======================= get方法======================== int* SliceDataIO::getSliceIndex(){ return this->_sliceIndex; } int*SliceDataIO::getLineIndex(){ return this->_lineIndex; } int* SliceDataIO::getCDPIndex(){ return this->_cdpIndex; } float*SliceDataIO::getX(){ return this->_Xcordinate; } float*SliceDataIO::getY(){ return this->_Ycordinate; } float*SliceDataIO::getTime() { return this->_time; } float*SliceDataIO::getValue() { return this->_value; } int SliceDataIO::getSampleNum(){ return this->_nsample; } // set方法 bool SliceDataIO::setData(vector<int> IndexVector, vector<float> XVector, vector<float> YVector, vector<int> LineVector, vector<int> CDPVector, vector<float> ValueVector, vector<float> TimeVector){ for(int isample=0; isample < this->_nsample;isample++){ this->_sliceIndex[isample] = IndexVector[isample]; this->_lineIndex[isample] = LineVector[isample]; this->_cdpIndex[isample] = CDPVector[isample]; this->_Xcordinate[isample] = XVector[isample]; this->_Ycordinate[isample] = YVector[isample]; this->_value[isample] = ValueVector[isample]; this->_time[isample] = TimeVector[isample]; } return true; } // 读取切片数据函数 SliceDataIO *readSliceData(const char *filenameInput){ int Index_temp = 0; float X_temp = 0.0f; float Y_temp = 0.0f; int CDP_temp = 0; int LINE_temp = 0; float Time_temp = 0.0f; float Value_temp = 0.0f; bool flag = true; int k = 0; int n1 = 1; int nPoint = 0; vector<int> IndexVector; vector<float> XVector; vector<float> YVector; vector<int> LineVector; vector<int> CDPVector; vector<float> ValueVector; vector<float> TimeVector; FILE *fp_input = NULL; fp_input = fopen(filenameInput, "rt"); if(fp_input==NULL){ printf("Can not open %s file!!!\n", filenameInput); return NULL; } fscanf(fp_input,"%*[^\n]%*c"); while(flag == true){ n1 = fscanf(fp_input,"%d %d %d %f %f %f %f",&Index_temp,&LINE_temp,&CDP_temp,&X_temp,&Y_temp,&Time_temp,&Value_temp); if(n1<0){ flag = false; }else{ IndexVector.push_back(Index_temp); LineVector.push_back(LINE_temp); CDPVector.push_back(CDP_temp); XVector.push_back(X_temp); YVector.push_back(Y_temp); TimeVector.push_back(Time_temp); ValueVector.push_back(Value_temp); k = k + 1; }//end if(n1<0) if(k%1000==0){ printf(" Read numTrace=%d\n",k); }//end if(k%1000==0) }//end while(flag == true) nPoint = ValueVector.size(); SliceDataIO *data = new SliceDataIO(nPoint); data->setData(IndexVector, XVector, YVector, LineVector, CDPVector, ValueVector, TimeVector); vector<int>().swap(IndexVector); vector<int>().swap(LineVector); vector<int>().swap(CDPVector); vector<float>().swap(XVector); vector<float>().swap(YVector); vector<float>().swap(TimeVector); vector<float>().swap(ValueVector); fclose(fp_input); return data; } // 写入切片数据 bool writeSliceData(const char *filenameOutput, SliceDataIO *slicedata){ int nsample = slicedata->getSampleNum(); int *Index = slicedata->getSliceIndex(); int *LineIndex = slicedata->getLineIndex(); int *CdpIndex = slicedata->getCDPIndex(); float *X = slicedata->getX(); float *Y = slicedata->getY(); float *Time = slicedata->getTime(); float *Value = slicedata->getValue(); FILE *fp_output = fopen(filenameOutput,"wt"); fprintf(fp_output,"Index Line CDP X Y Time(ms) Value\n"); for (int isample=0; isample<nsample; isample++){ fprintf(fp_output,"%d %d %d %f %f %f %f\n", Index[isample], LineIndex[isample], CdpIndex[isample],X[isample],Y[isample],Time[isample],Value[isample]); if (isample % 1000 == 0) { printf(" Write numTrace=%d\n", isample); }//end if(k%1000==0) } fclose(fp_output); return true; } 3 编写主函数main.cpp

#include"SliceCurvatrue.h" #include"SliceDataIO.h" int main(int argc, char *agrv) { SliceDataIO *slice = readSliceData("W11.slice"); // 读入切片数据 writeSliceData("W11copy.slice", slice); // 写入切片数据 delete slice; // 释放分配给类对象slice的动态内存空间 return 1; }

运行主函数之后,程序将读入W11.slice,并将切片数据写至W11copy.slice中。

delete:用以释放动态分配的内存空间,要求被释放的指针必须是指向动态分配的内存空间。

附录 vector用法 a.基本操作
  • 使用时需调用头文件#include<vector>中;
  • 创建vector对象,形如vector<int> vec,vector的元素可以是int,double,string或结构体;
  • 使用[ ]访问元素,如vec[0]
  • 尾部添加元素:vec.push_back(a)
  • 插入元素:vec.insert(vec.begin()+i,a) 在第i+1个元素前插入a
  • 删除元素;vec.erase(vec.begin()+2) 删除第3个元素;
  • 两vector交换数据:a.swap(b) 交换向量a和b的值;
  • 向量大小:vec.size()
  • 清空向量:vec.clear()
b.算法

需要头文件#include<algorithm>

  • 使用reverse将元素翻转:reverse(vec.begin(),vec.end())
  • 使用sort排序:sort(vec.begin(),vec.end())

本文共计4722个文字,预计阅读时间需要19分钟。

如何高效地C/C++编程读取地震切片数据?

SliceData IO 文档将介绍文本文档的读写,包括文本格式和文件的读写。常见文本资源主要有:层位(.txt)、切片(.txt)、测井(.las、.txt)、断层(.txt)等。这些资源实质上为表格(Table),由表头和数据组构成。

SliceData IO

本文档将介绍文本格式文件的读写,常见的文本资料主要有:

层位(.txt) 切片(.txt) 测井(.las.txt) 断层(.txt)等。这些资料实质上均为表格(Table),由表头和数据组成。

本次练习将对切片(Slice)文件进行读写操作,常见的切片数据样例如下:

Index Line CDP X Y Time(ms) Value 1 4386 2874 409455 4252075 4129.04 -0.7874 1 4386 2875 409455 4252087 4136.59 -1.2206 ... ... ... ... 9 5177 1708 429230 4237500 3273.81 1.1847 9 5177 1709 429230 4237513 3275.52 1.5910

新建头文件SliceDataIO.h与C++文件SliceDataIO.cpp,以及主函数main.cpp

1 编写头文件SliceData.h 1.1 程序描述、调用、声明、定义

/********************************************************************** * Copyright(C) 2018,Company All Rights Reserved * * @file : SliceData.cpp * * @brief : 实现文本数据的读、写操作 * * @version : 1.0 * * @author : Fan XinRan * * @date : 2022/2/8 星期二 * * Others : **********************************************************************/ #pragma once #include<stdio.h> //C Language header file #include<stdlib.h> #include<string.h> #include<math.h> #include<iostream> // C++ header file #include<vector> #include<algorithm> #include"alloc.h" // 用于创建多维数组 #define PI 3.141592654 #define EPS 0.000001 using namespace std; 1.2 定义类

描述了一种数据类型的全部属性(包括可使用它执行的操作),对象是根据这些描述创建的实体。

class Classname { // class + 类名 public: // 公有成员 在程序中类的外部是可访问的,可以不使用任何成员函数来设置和获取公有变量的值 float x; private: // 私有成员 私有成员变量或函数在类的外部是不可访问的,甚至不可查看的 float _y; protected: // 受保护成员 与私有成员相似,不同之处为,受保护成员在子类中是可访问的 float z; } (1) 私有成员

通常情况下都会设置类成员状态为私有(private),以保证良好的封装性。私有成员中的变量和函数一般以(_)开头。

class SliceDataIO{ // 定义一个名为SliceDataIO的类 private: // 私有成员 int *_sliceIndex; // 1 切片号 int *_lineIndex; // 2 线号 int *_cdpIndex; // 3 道号 float *_Xcordinate; // 4 X坐标 float *_Ycordinate; // 5 Y坐标 float *_time; // 6 时间 float *_value; // 7 属性值 int _nsample; // 采样点数 public: // 公有成员 ... }; (2) 公有成员

由于隐藏数据是OOP(面向对象编程)的主要目标之一,因此数据项通常放在私有部分。公有成员函数是程序和对象的私有成员之间的桥梁,通过设计公有成员函数以获取隐藏的数据。

class SliceDataIO{ private: ... public: // 公有成员 SliceDataIO(); // 默认构造函数 没有参数,将创建SliceDataIO类对象,但不初始化其成员 SliceDataIO(int nsample); // 创建一个具有nsample个采样点的类对象 ~SliceDataIO(); // 析构函数 // 获取数据get() int *getSliceIndex(); // 1 声明成员函数:获取切片号 int *getLineIndex(); // 2 ... int *getCDPIndex(); // 3 ... float *getX(); // 4 ... float *getY(); // 5 ... float *getTime(); // 6 ... float *getValue(); // 7 获取属性值 int getSampleNum(); // 声明成员函数:获取采样点数 // 设定数据set() bool setData(vector<int> IndexVector,vector<float> XVector,vector<float> YVector,vector<int> LineVector,vector<int> CDPVector,vector<float> ValueVector,vector<float> TimeVector); }

  1. 构造函数:

    • 是类的一种特殊的成员函数,它会在每次创建类的新对象时执行;
    • 构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。
    • 默认构造函数没有任何参数,带参数的构造函数则会在创建对象时为其赋初始值。
  2. 析构函数:

    • 是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行;
    • 析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数;
    • 析构函数完成清理工作,在跳出程序(比如关闭文件、释放内存等)前释放资源。
  3. vector(向量):是一个能够存放任意类型的动态数组,可在末尾附加新数据,或在中间插入新数据。

1.3 声明函数

声明读、写函数,其中读函数由SliceDataIO类实现。

SliceDataIO *readSliceData(const char *filenameInput); // read slice data from Inputfile bool writeSliceData(const char *filenameOutput, SliceDataIO *slicedata) // write slice data to Outputfile 完整代码

#pragma once #include<stdio.h> //C Language header file #include<stdlib.h> #include<string.h> #include<math.h> #include<iostream> //C++ header file #include<vector> #include<algorithm> #include"alloc.h" #define PI 3.141592654 // 定义全局常量 #define EPS 0.000001 using namespace std; // 声明命名空间 class SliceDataIO{ // 定义一个名为SliceDataIO的类,用于切片数据的读写 public: // 公有成员 SliceDataIO(); SliceDataIO(int nsample); ~SliceDataIO(); // 获取隐藏数据 int *getSliceIndex(); int *getLineIndex(); int *getCDPIndex(); float *getX(); float *getY(); float *getTime(); float *getValue(); int getSampleNum(); // 设定数据 bool setData(vector<int> IndexVector,vector<float> XVector,vector<float> YVector,vector<int> LineVector,vector<int> CDPVector,vector<float> ValueVector,vector<float> TimeVector); private: // 私有成员 // 声明私有变量,包括切片号、线号、道号等 int *_sliceIndex; int *_lineIndex; int *_cdpIndex; float *_Xcordinate; float *_Ycordinate; float *_time; float *_value; int _nsample; }; // 声明读、写函数 SliceDataIO *readSliceData(const char *filenameInput); bool writeSliceData(const char *filenameOutput, SliceDataIO *slicedata); 2 编写C++文件SliceData.cpp 2.1 定义类成员函数

类成员函数是类的一个成员,它可以操作类的任意对象,也可以访问对象中的所有成员。成员函数可以定义在类定义内部,或者单独使用作用域解析运算符(::)来定义,此时(::)前须加类名以标识函数所属的类。

如何高效地C/C++编程读取地震切片数据?

(1)构造函数

// 默认构造函数 SliceDataIO::SliceDataIO(){ // 默认构造函数,将成员初始化为NULL或0 this->_sliceIndex = NULL; // 1 初始化切片号 this->_lineIndex = NULL; // 2 初始化线号 this->_cdpIndex = NULL; // 3 初始化道号 this->_Xcordinate = NULL; // 4 初始化X坐标 this->_Ycordinate = NULL; // 5 初始化Y坐标 this->_time = NULL; // 6 初始化时间值 this->_value = NULL; // 7 初始化属性值 this->_nsample = 0; // 初始化采样点数 }

// 带参数的构造函数 SliceDataIO::SliceDataIO(int nsample){ // 创建一个具有nsample个采样点的类对象,并为其成员分配内存 this->_nsample = nsample; // 输入采样点数nsample,根据采样点数分配内存 this->_sliceIndex = (int*)calloc(this->_nsample, sizeof(int)); this->_lineIndex = (int*)calloc(this->_nsample,sizeof(int)); this->_cdpIndex= (int*)calloc(this->_nsample, sizeof(int)); this->_Xcordinate= (float*)calloc(this->_nsample, sizeof(float)); this->_Ycordinate = (float*)calloc(this->_nsample, sizeof(float)); this->_time = (float*)calloc(this->_nsample,sizeof(float)); this->_value= (float*)calloc(this->_nsample, sizeof(float)); } (2)析构函数

// 析构函数 SliceDataIO::~SliceDataIO(){ // 析构函数完成清理工作 if(this->_cdpIndex!=NULL){ free(this->_cdpIndex); // 释放内存 this->_cdpIndex = NULL; // 成员置空 } if(this->_lineIndex!=NULL){ free(this->_lineIndex); this->_lineIndex = NULL; } if(this->_sliceIndex!=NULL){ free(this->_sliceIndex); this->_sliceIndex = NULL; } if(this->_Xcordinate!=NULL){ free(this->_Xcordinate); this->_Xcordinate = NULL; } if(this->_Ycordinate!=NULL){ free(this->_Ycordinate); this->_Ycordinate = NULL; } if(this->_time!=NULL){ free(this->_time); this->_time = NULL; } if(this->_value!=NULL){ free(this->_value); this->_value = NULL; } }

  1. this:
    • 它是一种特殊的指针,每一个对象都能通过 this 指针来访问自己的地址;
    • this 指针是所有成员函数的隐含参数,因此,在成员函数内部,它可以用来指向调用对象;
    • 只有成员函数才有 this 指针。
  2. ->:称为箭头运算符。在调用类成员时,使用点运算符(.)或箭头运算符(->),点运算符应用于实际的对象;箭头运算符与一个指向对象的指针一起使用。
(3)get()方法函数

首先是get方法,用于获取数据;

int* SliceDataIO::getSliceIndex(){ //定义SliceDataIO的类成员函数getSliceIndex以获取切片号 return this->_sliceIndex; } int*SliceDataIO::getLineIndex(){ return this->_lineIndex; } int* SliceDataIO::getCDPIndex(){ return this->_cdpIndex; } float*SliceDataIO::getX(){ return this->_Xcordinate; } float*SliceDataIO::getY(){ return this->_Ycordinate; } float*SliceDataIO::getTime() { return this->_time; } float*SliceDataIO::getValue() { return this->_value; } int SliceDataIO::getSampleNum(){ return this->_nsample; } (4)set()方法函数

然后是set方法,用于指定数据为当前类对象的值。

bool SliceDataIO::setData(vector<int> IndexVector, vector<float> XVector, vector<float> YVector, vector<int> LineVector, vector<int> CDPVector, vector<float> ValueVector, vector<float> TimeVector){ // 函数接收若干个向量,并将向量值赋给当前的类对象 for(int isample=0; isample < this->_nsample;isample++){ this->_sliceIndex[isample] = IndexVector[isample]; this->_lineIndex[isample] = LineVector[isample]; this->_cdpIndex[isample] = CDPVector[isample]; this->_Xcordinate[isample] = XVector[isample]; this->_Ycordinate[isample] = YVector[isample]; this->_value[isample] = ValueVector[isample]; this->_time[isample] = TimeVector[isample]; } return true; } 2.2 定义读取函数

SliceDataIO *readSliceData(const char *filenameInput){ // 定义读取Slice数据的函数 int Index_temp = 0; // 创建待处理的切片参数,并按类型分别初始化。用于临时存放单一采样点数据 int CDP_temp = 0; int LINE_temp = 0; float X_temp = 0.0f; float Y_temp = 0.0f; float Time_temp = 0.0f; float Value_temp = 0.0f; bool flag = true; // 判断程序是否正常运行 int k = 0; // 当前循环次数 int n1 = 1; // 判定输入是否正常 int nPoint = 0; // 向量(vector)中存放的样本点数 vector<int> IndexVector; // 分别创建vector用于存放切片号、道号、线号等信息 vector<int> LineVector; vector<int> CDPVector; vector<float> XVector; vector<float> YVector; vector<float> TimeVector; vector<float> ValueVector; FILE *fp_input = NULL; // 创建输入指针 fp_input = fopen(filenameInput, "rt"); // 以"rt"方式,即读取文本的方式打开文件 if(fp_input==NULL){ // 非空判定 printf("Can not open %s file!!!\n", filenameInput); return NULL; } fscanf(fp_input,"%*[^\n]%*c"); // " "内为固定正则表达,用于忽略********************************* while(flag == true){ // 当程序正常运行时 n1 = fscanf(fp_input,"%d %d %d %f %f %f %f", &Index_temp,&LINE_temp,&CDP_temp,&X_temp,&Y_temp,&Time_temp,&Value_temp); // 从输入流中分别获取需要的数据 if(n1<0){ flag = false; // 如果读取异常,循环中止 }else{ IndexVector.push_back(Index_temp); LineVector.push_back(LINE_temp); CDPVector.push_back(CDP_temp); XVector.push_back(X_temp); YVector.push_back(Y_temp); TimeVector.push_back(Time_temp); ValueVector.push_back(Value_temp); // 读取正常,追加新数据到向量中 k = k + 1; }//end if(n1<0) if(k%1000==0){ // 每1000轮显示一次进度 printf(" Read numTrace=%d\n",k); }//end if(k%1000==0) }//end while(flag == true) nPoint = ValueVector.size(); // 获取vector中存放的数据条数 SliceDataIO *data = new SliceDataIO(nPoint); // 分配内存 // 为新建的空白对象data设定值,类似粘贴 data->setData(IndexVector, XVector, YVector, LineVector, CDPVector, ValueVector, TimeVector); vector<int>().swap(IndexVector); // 每个向量与空向量交换,即将存有数据的向量置空 vector<int>().swap(LineVector); vector<int>().swap(CDPVector); vector<float>().swap(XVector); vector<float>().swap(YVector); vector<float>().swap(TimeVector); vector<float>().swap(ValueVector); fclose(fp_input); // 关闭输入文件指针 return data; // 返回数据data }

  1. fscanf()从流 stream 读取格式化输入;

    int fscanf(FILE *stream, const char *format, ...)

    • stream-- 指向FILE对象的指针;

    • format-- 这是 C 字符串,包含了以下各项中的一个或多个:空格字符、非空格字符和 format 说明符;

      format说明符形式为 [=%[*][width][modifiers]type=]

  2. new:为任意的数据类型动态分配内存;用法有以下两种:

    • Type *p = new Type;其中,Type 是任意类型名,p 是类型为 Type 的指针;
    • Type *p =new Type[N];用来动态分配一个任意大小的数组,N 代表元素个数;

    malloc() 函数相比,new 的主要的优点是,其不只分配了内存,还创建了对象。

2.3 定义写入函数

bool writeSliceData(const char *filenameOutput, SliceDataIO *slicedata){ int nsample = slicedata->getSampleNum(); // 从类对象slicedata中get各类数据 int *Index = slicedata->getSliceIndex(); int *LineIndex = slicedata->getLineIndex(); int *CdpIndex = slicedata->getCDPIndex(); float *X = slicedata->getX(); float *Y = slicedata->getY(); float *Time = slicedata->getTime(); float *Value = slicedata->getValue(); FILE *fp_output = fopen(filenameOutput,"wt"); //以写入文本的方式打开Outputfile fprintf(fp_output,"Index Line CDP X Y Time(ms) Value\n"); // 先写入表头 for (int isample=0; isample<nsample; isample++){ //遍历类对象中每一个采样点样本 fprintf(fp_output,"%d %d %d %f %f %f %f\n", Index[isample], LineIndex[isample], CdpIndex[isample],X[isample],Y[isample],Time[isample],Value[isample]); //写入到输出流中 if (isample % 1000 == 0) { // 同样,每迭代1000次打印一次进度 printf(" Write numTrace=%d\n", isample); }//end if(k%1000==0) } fclose(fp_output); // 关闭输出文件指针 return true; }

fprintf:发送格式化输出到流 stream 中,用法与fscanf相似;

int fprintf(FILE *stream, const char *format, ...)

  • stream-- 指向FILE对象的指针;

  • format-- 包含了要被写入到流stream中的文本。由以下各项中的一个或多个组成:空格字符、非空格字符和format说明符;

    format说明符形式为 [=%[*][width][modifiers]type=]

完整代码

/***************************************************************************** Function: SliceDataIO Description: read and write slice data Input: const char *filenameInput [in] input filename (.txt) Output: const char *filenameOutput[out] output filename (.txt) Return: bool true program success bool false program failed Author: Fan XinRan Date : 2022/2/8 Others: *****************************************************************************/ #include "SliceDataIO.h" //构造函数 SliceDataIO::SliceDataIO(){ this->_cdpIndex = NULL; this->_lineIndex = NULL; this->_sliceIndex = NULL; this->_Xcordinate = NULL; this->_Ycordinate = NULL; this->_time = NULL; this->_value = NULL; this->_nsample = 0; } //带参数nsample的构造函数 SliceDataIO::SliceDataIO(int nsample){ this->_nsample = nsample; this->_sliceIndex = (int*)calloc(this->_nsample, sizeof(int)); this->_lineIndex = (int*)calloc(this->_nsample,sizeof(int)); this->_cdpIndex= (int*)calloc(this->_nsample, sizeof(int)); this->_Xcordinate= (float*)calloc(this->_nsample, sizeof(float)); this->_Ycordinate = (float*)calloc(this->_nsample, sizeof(float)); this->_time = (float*)calloc(this->_nsample,sizeof(float)); this->_value= (float*)calloc(this->_nsample, sizeof(float)); } //析构函数 SliceDataIO::~SliceDataIO(){ if(this->_cdpIndex!=NULL){ free(this->_cdpIndex); this->_cdpIndex = NULL; } if(this->_lineIndex!=NULL){ free(this->_lineIndex); this->_lineIndex = NULL; } if(this->_sliceIndex!=NULL){ free(this->_sliceIndex); this->_sliceIndex = NULL; } if(this->_Xcordinate!=NULL){ free(this->_Xcordinate); this->_Xcordinate = NULL; } if(this->_Ycordinate!=NULL){ free(this->_Ycordinate); this->_Ycordinate = NULL; } if(this->_time!=NULL){ free(this->_time); this->_time = NULL; } if(this->_value!=NULL){ free(this->_value); this->_value = NULL; } } //======================= get方法======================== int* SliceDataIO::getSliceIndex(){ return this->_sliceIndex; } int*SliceDataIO::getLineIndex(){ return this->_lineIndex; } int* SliceDataIO::getCDPIndex(){ return this->_cdpIndex; } float*SliceDataIO::getX(){ return this->_Xcordinate; } float*SliceDataIO::getY(){ return this->_Ycordinate; } float*SliceDataIO::getTime() { return this->_time; } float*SliceDataIO::getValue() { return this->_value; } int SliceDataIO::getSampleNum(){ return this->_nsample; } // set方法 bool SliceDataIO::setData(vector<int> IndexVector, vector<float> XVector, vector<float> YVector, vector<int> LineVector, vector<int> CDPVector, vector<float> ValueVector, vector<float> TimeVector){ for(int isample=0; isample < this->_nsample;isample++){ this->_sliceIndex[isample] = IndexVector[isample]; this->_lineIndex[isample] = LineVector[isample]; this->_cdpIndex[isample] = CDPVector[isample]; this->_Xcordinate[isample] = XVector[isample]; this->_Ycordinate[isample] = YVector[isample]; this->_value[isample] = ValueVector[isample]; this->_time[isample] = TimeVector[isample]; } return true; } // 读取切片数据函数 SliceDataIO *readSliceData(const char *filenameInput){ int Index_temp = 0; float X_temp = 0.0f; float Y_temp = 0.0f; int CDP_temp = 0; int LINE_temp = 0; float Time_temp = 0.0f; float Value_temp = 0.0f; bool flag = true; int k = 0; int n1 = 1; int nPoint = 0; vector<int> IndexVector; vector<float> XVector; vector<float> YVector; vector<int> LineVector; vector<int> CDPVector; vector<float> ValueVector; vector<float> TimeVector; FILE *fp_input = NULL; fp_input = fopen(filenameInput, "rt"); if(fp_input==NULL){ printf("Can not open %s file!!!\n", filenameInput); return NULL; } fscanf(fp_input,"%*[^\n]%*c"); while(flag == true){ n1 = fscanf(fp_input,"%d %d %d %f %f %f %f",&Index_temp,&LINE_temp,&CDP_temp,&X_temp,&Y_temp,&Time_temp,&Value_temp); if(n1<0){ flag = false; }else{ IndexVector.push_back(Index_temp); LineVector.push_back(LINE_temp); CDPVector.push_back(CDP_temp); XVector.push_back(X_temp); YVector.push_back(Y_temp); TimeVector.push_back(Time_temp); ValueVector.push_back(Value_temp); k = k + 1; }//end if(n1<0) if(k%1000==0){ printf(" Read numTrace=%d\n",k); }//end if(k%1000==0) }//end while(flag == true) nPoint = ValueVector.size(); SliceDataIO *data = new SliceDataIO(nPoint); data->setData(IndexVector, XVector, YVector, LineVector, CDPVector, ValueVector, TimeVector); vector<int>().swap(IndexVector); vector<int>().swap(LineVector); vector<int>().swap(CDPVector); vector<float>().swap(XVector); vector<float>().swap(YVector); vector<float>().swap(TimeVector); vector<float>().swap(ValueVector); fclose(fp_input); return data; } // 写入切片数据 bool writeSliceData(const char *filenameOutput, SliceDataIO *slicedata){ int nsample = slicedata->getSampleNum(); int *Index = slicedata->getSliceIndex(); int *LineIndex = slicedata->getLineIndex(); int *CdpIndex = slicedata->getCDPIndex(); float *X = slicedata->getX(); float *Y = slicedata->getY(); float *Time = slicedata->getTime(); float *Value = slicedata->getValue(); FILE *fp_output = fopen(filenameOutput,"wt"); fprintf(fp_output,"Index Line CDP X Y Time(ms) Value\n"); for (int isample=0; isample<nsample; isample++){ fprintf(fp_output,"%d %d %d %f %f %f %f\n", Index[isample], LineIndex[isample], CdpIndex[isample],X[isample],Y[isample],Time[isample],Value[isample]); if (isample % 1000 == 0) { printf(" Write numTrace=%d\n", isample); }//end if(k%1000==0) } fclose(fp_output); return true; } 3 编写主函数main.cpp

#include"SliceCurvatrue.h" #include"SliceDataIO.h" int main(int argc, char *agrv) { SliceDataIO *slice = readSliceData("W11.slice"); // 读入切片数据 writeSliceData("W11copy.slice", slice); // 写入切片数据 delete slice; // 释放分配给类对象slice的动态内存空间 return 1; }

运行主函数之后,程序将读入W11.slice,并将切片数据写至W11copy.slice中。

delete:用以释放动态分配的内存空间,要求被释放的指针必须是指向动态分配的内存空间。

附录 vector用法 a.基本操作
  • 使用时需调用头文件#include<vector>中;
  • 创建vector对象,形如vector<int> vec,vector的元素可以是int,double,string或结构体;
  • 使用[ ]访问元素,如vec[0]
  • 尾部添加元素:vec.push_back(a)
  • 插入元素:vec.insert(vec.begin()+i,a) 在第i+1个元素前插入a
  • 删除元素;vec.erase(vec.begin()+2) 删除第3个元素;
  • 两vector交换数据:a.swap(b) 交换向量a和b的值;
  • 向量大小:vec.size()
  • 清空向量:vec.clear()
b.算法

需要头文件#include<algorithm>

  • 使用reverse将元素翻转:reverse(vec.begin(),vec.end())
  • 使用sort排序:sort(vec.begin(),vec.end())