C/C++语言读取SEGY文件笔记(一)
SEGY IO
推荐采用的IDE为Visual studio(VS),本文档将介绍SEGY文件的读取与写入过程,即SEGY文件的复制。
因此,新建头文件ReadSeismic.h与C++文件ReadSeismic.cpp,以及主函数main.cpp。
1 SEGY简介
标准SEGY文件一般包括三部分:卷头、道头与地震道数据;
| 卷头(File Header) | EBCDIC文件头(3200字节) | 保存一些对地震数据体进行描述的信息 |
| 二进制文件头(400字节) | 存储描述SEGY文件的数据格式、采样点数、采样间隔、测量单位等信息 | |
| 道头(Trace Header) | 240字节 | 存储某一地震道对应的线号、道号、采样点数、大地坐标等信息 |
| 地震道数据(Data) | 若干采样点(1000、2000) | 是对地震信号的波形按一定时间间隔Δt进行取样所得的一系列离散振幅值 |
SEGY文件由卷头及n个地震道记录组成:

SEGY样本示例:

图中横轴上730--->Line,1580、1582--->CDP,纵轴上1240、1260--->Time
2 头文件ReadSeismic.h的编写及其规范
2.1 必要的说明
/**********************************************************************
* Copyright(C) 2018,Company All Rights Reserved (1)版权说明
*
* @file : ReadSeismic.cpp (2) 文件名
*
* @brief : 实现地震数据的读、写操作 (3) 该文件主要功能简介
*
* @version : 1.0 (4) 版本信息
*
* @author : Fan XinRan (5) 创建作者
*
* @date : 2022/2/8 星期二 (6) 创建时间
*
* Others : (7) 备注、改动信息等
**********************************************************************/
2.2 调用需要的C/C++头文件
//调用需要的C头文件
#include<stdio.h> //C Language header file
#include<stdlib.h>
#include<string.h>
#include<math.h>
//调用需要的C++头文件
#include<iostream> // C++ header file
#include<vector>
#include<algorithm>
2.3 调用需要的非标准库头文件
注意使用双引号(" "),并将这些头文件添加到项目文件夹中。对于每个调用的非标准库,需要给出必要的注释说明。
#include"alloc.h" // 用于创建多维数组
#include"segy.h" // 包含segy与bhed结构体,用于提取卷头和道头中采集、存储的信息
2.4 定义全局变量及命名空间
对于代码中用到的物理量、常数等,使用#define定义常量并加以说明,避免函数中出现意义不明的常量。
#define PI 3.141592654 //Constant Number Definition
#define EPS 0.0000001
using namespace std;
2.5 声明函数
bool copySeismicData(const char *filenameInput, const char *filenameOutput); //Copy seismic data from Inputfile to Outputfile
完整代码
/**********************************************************************
* Copyright(C) 2018,Company All Rights Reserved
*
* @file : ReadSeismic.cpp
*
* @brief : 实现地震数据的读、写操作
*
* @version : 1.0
*
* @author : Fan XinRan
*
* @date : 2022/2/8 星期二
*
* Others :
**********************************************************************/
//(1)调用需要的C头文件
#include<stdio.h> // C Language header file
#include<stdlib.h>
#include<string.h>
#include<math.h>
//(2)调用需要的C++头文件
#include<iostream> // C++ header file
#include<vector>
#include<algorithm>
//(3)调用需要的非标准库头文件
#include"alloc.h" // project header file
#include"segy.h"
//(4)定义全局常量
#define PI 3.141592654 // Constant Number Definition
#define EPS 0.0000001
//(5)声明命名空间
using namespace std;
//(6)声明函数名、输入、输出及其类型
bool copySeismicData(const char *filenameInput, const char *filenameOutput); //Copy seismic data from Inputfile to Outputfile
3 C++文件ReadSeismic.cpp的编写及其规范
3.1 必要的说明
/*************************************************************************************************************
Function: copySeismicData (1)函数名
Description: copy segy file from input data to output data (2)简要描述其功能
Input:
const char *filenameInput [in] input filename (.segy) (3)输入变量及输入文件类型
Output:
const char *filenameOutput[out] output filename (.segy) (4)输出变量及输出文件类型
Return:
bool true program success
bool false program failed (5)返回值及其说明
Author: Fan XinRan (6)创建作者
Date : 2022/2/8 (7)创建时间
Others: (8)备注、改动信息等
*************************************************************************************************************/
3.2 定义读、写函数
#include "ReadSeismic.h"
bool copySeismicData(const char *filenameInput, const char *filenameOutput){
//实现代码
...
}
(1)定义待使用的结构体变量、数值型变量
bhed 与 segy均为定义在segy.h中的结构体(structure),分别包含了二进制卷头信息与道头信息,使用成员访问运算符(.)获取其内容;
使用unsigned int 声明整型变量,使用long long 或__int64声明SEGY文件字节数、地震道字节数,防止数据量超出范围,并且尽可能初始化各变量。
bhed fileheader; // file header 卷头
segy traceheader; // trace header 道头
unsigned int nt=0; // number of sample 采样点数
unsigned int sizefileheader=sizeof(fileheader); // size of fileheader;
unsigned int sizetraceheader=sizeof(traceheader); // size of traceheader;
unsigned int ncdp = 0; // number of cdp 道数
long long size_file = 0; //size of input file
long long size_trace = 0; //size of per-trace
(2)新建指针变量
在读、写地震道数据这一任务中,需要用到输入指针、输出指针以及逐条写入时的道号指针,三个指针变量。
FILE *fpinput = NULL; // input file pointer
FILE *fpoutput = NULL; //output file pointer
float *dataInput = NULL; //input data pointer
(3)打开输入、输出文件指针
fpinput = fopen(filenameInput, "rb"); //open input file pointer
fpoutput = fopen(filenameOutput,"wb"); //open output file pointer
//读写操作
...
//fopen()与fclose()成对出现,在对文件的操作完成后切记关闭文件
fclose(fpinput); //close input file pointer
fclose(fpoutput); //close output file pointer
fopen()的参数详解:
fopen(const char *filename, const char *mode)
- filename -- 要打开的文件名称;
- mode -- 文件访问模式;
(4)判断文件打开情况
if(fpinput==NULL){ //如果文件指针为NULL
printf("Cannot open %s file\n", filenameInput); //打印“文件打开失败”
return false; //结束程序
}
if(fpoutput==NULL){
printf("Cannot open %s file\n", filenameOutput);
return false;
}
(5)读取/计算卷、道信息
fread(&fileheader,sizefileheader,1,fpinput); // 从输入流(fpinput)中读取卷头信息到指定地址---->fileheader
nt = fileheader.hns; //从卷头信息中获取采样点数
_fseeki64(fpinput,0,SEEK_END); // 从文件末尾偏移这个结构体0个长度给文件指针fpinput,即fpinput此时指向文件尾
size_file = _ftelli64(fpinput); // 返回当前文件位置,即文件总字节数
size_trace = nt*sizeof(float)+sizetraceheader; // 每一道的字节数 = 采样点字节数+道头字节数
ncdp = (size_file - (long long)sizefileheader)/size_trace; // 道数 = (文件总字节数 - 卷头字节数)/每一道的字节数
_fseeki64(fpinput,sizefileheader,SEEK_SET); // 从文件开头偏移sizefileheader(卷头字节数)个长度给指针fpinput,即fpinput此时指向第一道的开始
fwrite(&fileheader, sizefileheader, 1, fpoutput); // 先写入卷头
fread()从给定流读取数据到指针所指向的数组中;fread(*ptr, size, nmemb,*stream)- ptr -- 指向带有最小尺寸 size*nmemb 字节的内存块的指针;
- size -- 要读取的每个元素的大小,以字节为单位。
- nmemb -- 元素的个数,每个元素的大小为 size 字节;
- stream -- 指向 FILE 对象的指针。
fwrite(*ptr, size, nmemb,*stream)参数与fread()相同,把ptr所指向的数组中的数据写入到给定流stream中;_fseeki64的用法与fseek相同,表示从文件指定位置偏移一定字节数;前者具有更高的兼容性;_ftelli64与ftell同理,返回给定流的当前文件位置;_fseeki64(*stream, offset, whence)stream -- 指向 FILE 对象的指针;
offset -- 相对 whence 的偏移量,以字节为单位;
whence -- 表示开始添加偏移 offset 的位置。一般定义为
SEEK_SET(文件开头)、SEEK_CUR(文件指针的当前位置)、SEEK_END(文件末尾)三类常量。
(6)遍历每一条地震道,读、写数据
dataInput=(float*)calloc(nt,sizeof(float)); // 分配nt(采样点数)个元素所需的内存空间,用来存放单条地震道数据
for(int itrace= 0; itrace< ncdp; itrace++){
fread(&traceheader, sizetraceheader,1, fpinput); // 指针fpinput自第一道道头开始移动,读取数据到traceheader中
fread(dataInput,nt*sizeof(float),1,fpinput); // 指针fpinput移动到道头末尾(数据开头),读入nt个采样点的数据到dataInput中
fwrite(&traceheader, sizetraceheader, 1, fpoutput);// 写入某一道头
fwrite(dataInput, nt * sizeof(float), 1, fpoutput);// 写入某一道地震数据
}//end for(int itrace= 0; itrace< ncdp; itrace++)
// 在每个循环末尾的"}"添加备注,便于寻找和区分
//分配内存calloc()与释放内存free()配合使用,在写操作完成后释放内存
free(dataInput); // free data input pointer
calloc(num,size):在内存的动态存储区中分配num个长度为size的连续空间,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL;malloc(size):功能与calloc()相似,不同之处是malloc()不会设置内存为零,而calloc()会设置分配的内存为零。
完整代码
/*****************************************************************************
Function: copySeismicData
Description: copy segy file from input data to output data
Input:
const char *filenameInput [in] input filename (.segy)
Output:
const char *filenameOutput[out] output filename (.segy)
Return:
bool true program success
bool false program failed
Author: Fan XinRan
Date : 2022/2/8
Others:
*****************************************************************************/
#include "ReadSeismic.h"
bool copySeismicData(const char *filenameInput, const char *filenameOutput){
bhed fileheader; // file header
segy traceheader; // trace header
unsigned int nt=0; // number of sample
unsigned int sizetraceheader=sizeof(traceheader); // size of traceheader;
unsigned int sizefileheader=sizeof(fileheader); // size of fileheader;
unsigned int ncdp = 0; // number of cdp
long long size_file = 0; //size of input file
long long size_trace = 0; //size of per-trace
FILE *fpinput = NULL; // input file pointer
FILE *fpoutput = NULL; //output file pointer
float *dataInput = NULL; //input data pointer
fpinput = fopen(filenameInput, "rb"); //open input file pointer
fpoutput = fopen(filenameOutput,"wb"); //open output file pointer
if(fpinput==NULL){
printf("Cannot open %s file\n", filenameInput);
return false;
}
if(fpoutput==NULL){
printf("Cannot open %s file\n", filenameOutput);
return false;
}
fread(&fileheader,sizefileheader,1,fpinput);
nt = fileheader.hns;
_fseeki64(fpinput,0,SEEK_END);
size_file = _ftelli64(fpinput);
size_trace = nt*sizeof(float)+sizetraceheader;
ncdp = (size_file - (long long)sizefileheader)/size_trace;
_fseeki64(fpinput,sizefileheader,SEEK_SET);
fwrite(&fileheader, sizefileheader, 1, fpoutput);
dataInput=(float*)calloc(nt,sizeof(float));
for(int itrace= 0; itrace< ncdp; itrace++){
fread(&traceheader, sizetraceheader,1, fpinput);
fread(dataInput,nt*sizeof(float),1,fpinput);
fwrite(&traceheader, sizetraceheader, 1, fpoutput);
fwrite(dataInput, nt * sizeof(float), 1, fpoutput);
}//end for(int itrace= 0; itrace< ncdp; itrace++)
free(dataInput); // free data input pointer
fclose(fpinput); //close input file pointer
fclose(fpoutput); //close output file pointer
return true;
}
3 主函数main.cpp及运行结果
#include"ReadSeismic.h"
void main(){
copySeismicData("Demo.segy","Output.segy");
}
运行主函数后,程序会读入OVT-BZ19-6-1_pc.segy,再写入到Output.segy,从而完成对Segy文件的复制。
附录
I SEGY文件卷头与道头中常用的属性
| 属性 | 变量名 | 位置/字节 | 备注 |
|---|---|---|---|
| 采样点 | hns | 卷头 | 此卷中每道的采样点数 |
| 格式 | format | 卷头 | ![]() |
| 线号 | fldr | 道头/9-12 | - |
| 道号 | cdp | 道头/21-24 | - |
| 采样点数 | nhs | 道头/33-34 | - |
| 横坐标 | sx | 道头/73-76 | - |
| 纵坐标 | sy | 道头/77-80 | - |
| 采样点数 | ns | 道头/115-116 | - |
| 采样间隔 | dt | 道头/117-118 | - |
| 增益 | gain | 道头/119-120 | 1 = yes ; 2 = no |
II 文件打开模式
| 模式 | 描述 |
|---|---|
| "r" | 以只读方式打开文件,该文件必须存在。 |
| "r+" | 以可读写方式打开文件,该文件必须存在。 |
| "rb" | 以只读方式打开一个二进制文件,只允许读数据。 |
| "w" | 创建一个用于写入的空文件。如果文件名称与已存在的文件相同,则会删除已有文件的内容,文件被视为一个新的空文件。 |
| "w+" | 创建一个用于读写的空文件。 |
| "wb" | 只写打开或新建一个二进制文件,只允许写数据。 |
| "a" | 追加到一个文件;写操作向文件末尾追加数据。如果文件不存在,则创建文件。 |
| "a+" | 打开一个用于读取和追加的文件。 |
| "rw+" | 读写打开一个文本文件,允许读和写。 |
C/C++语言读取SEGY文件笔记(一)的更多相关文章
- C/C++语言读取SEGY文件(二)
SEGY IO (2D) 本文档将介绍SEGY的读取与写入过程,即SEGY文件的复制,并且在实现过程采用采样点×道数二维数组的形式读写. 新建头文件SegyDataIO2D.h与C++文件SegyDa ...
- C/C++读取SEGY文件(三)
SEGY IO (IBM&PC) 本文档将介绍SEGY的读取与写入过程,其中包括IBM与PC两种数据格式的转换. 程序将调用IEEE2IBM.cpp文件完成IBM与PC格式的互相转换. 新建头 ...
- R语言读取excel文件的3种方法
R读取excel文件中数据的方法: 电脑有一个excel文件,原始的文件路径是:E:\R workshop\mydata\biom excel数据为5乘2阶矩阵,元素为 ...
- C语言读取PE文件信息(一)
接下来的内容来源于对该博客文章http://www.pediy.com/kssd/pediy06/pediy7006.htm的解析. 一.打印Sections信息.下面的程序打印出Windows_Gr ...
- R语言读取EXCEL文件的各种方法
路径问题 原始文件路径C:\Users\air\Desktop\1.txt R中有两种方法读取该路径 C:\\Users\\air\\Desktop\\1.txt C:/Users/air/Deskt ...
- R语言读取本地文件注意事项
R里面应该用/,而不是\ ,或者用两个\\ R区分大小写,所以应该用C:,而不是c:
- c语言读取一个文件夹下的全部文件(jpg / png 文件)
#include <cstdio> #include <cstring> #include <unistd.h> #include<dirent.h> ...
- C语言读取写入CSV文件 [一]基础篇
本系列文章目录 [一] 基础篇 [二] 进阶篇--写入CSV [三] 进阶篇--读取CSV 什么是CSV? CSV 是一种以纯文本形式存储的表格数据,具体介绍如下(来自维基百科): 逗号分隔值(Com ...
- R语言笔记004——R批量读取txt文件
R批量读取txt文件 本文数据,代码都是参考的是大音如霜公众号,只是自己跟着做了一遍. path<-'C:\\Users\\Administrator\\Desktop\\docs' docs& ...
随机推荐
- VMware14安装windows7的详细过程
感谢大佬:https://blog.csdn.net/u012230668/article/details/81701893 一.安装VMware虚拟机,以及下载一份ghost win7系统 下载地址 ...
- Tomcat部署时war和war exploded区别以及打包后路径问题
感谢原文作者:keven_deng 原文链接:https://blog.csdn.net/keven_deng/article/details/104830664 war和war exploded的区 ...
- 定制博客CSS样式
首先你需要添加页面CSS代码
- netty系列之:channel和channelGroup
目录 简介 神龙见首不见尾的channel channel和channelGroup channelGroup的基本使用 将关闭的channel自动移出 同时关闭serverChannel和accep ...
- Solution -「CF 510E」Fox And Dinner
\(\mathcal{Description}\) Link. 给定正整数集合 \(\{a_n\}\),求一种把这些数放置在任意多个圆环上的方案,使得每个环的大小大于 \(2\) 且环上相邻两 ...
- 暑假撸系统3- petty热更新 mybatis自动填充时间字段!
经过了昨天纠结技术选型,和一大堆xml配置,终于把架子搭好了.因为最近一次做java项目也在好多年以前了(毕竟用了pytohn以后谁也不想再回来java了),java的生态发生了长足的进步,本来想从原 ...
- python控制浏览器上传文件
自动化爬虫方法和库很多,难点大多数在登录.可以大致分为:普通验证码,扫码登录,QQ一键登录,拖动验证,无痕验证,人工识别(比如12306登录) 万能大法可以破解一切以上需求,自动控制浏览器行为 参考文 ...
- 对称加密算法之DES算法
数据加密标准(data encryption standard): DES是一种分组加密算法,输入的明文为64位,密钥为56位,生成的密文为64位. DES对64位的明文分组进行操作.通过一个初始置换 ...
- 第六题 Z字走法
我和答案第一种解法是很相似的 但是时间 和空间都被大部分人击败了. 思路就是用一个标记 为0就竖着走 为1就斜着走 把二维数组填满 我觉得难点在于PHYTON如何创建一个二维数组 而且是不定长的 ...
- c# 编程学习(五)
使用复合赋值和循环语句 使用 while 语句,可在条件为 true 的前提下重复运行一个语句.while 语句的语法如下: while ( booleanExpression ) statemen ...
