a
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
# 数据导出
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
|
||||
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
|
||||
- [excel.cpp](file://cpp/Tools/excel.cpp)
|
||||
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
|
||||
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
|
||||
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
|
||||
- [Rsp2DTd.cpp](file://cpp/ProblemZone/Rsp2DTd.cpp)
|
||||
- [RspCETd.cpp](file://cpp/ProblemZone/RspCETd.cpp)
|
||||
- [SP2DTd.cpp](file://cpp/ProblemZone/SP2DTd.cpp)
|
||||
- [TdManager.h](file://h/TdManager.h)
|
||||
- [IOManager.h](file://h/IOManager.h)
|
||||
- [excel.h](file://h/excel.h)
|
||||
- [OperTxtFile.h](file://h/OperTxtFile.h)
|
||||
- [OperUrfFile.h](file://h/OperUrfFile.h)
|
||||
- [ioexpdlg.cpp](file://cpp/Views/ioexpdlg.cpp)
|
||||
- [ioexpdmsdlg.cpp](file://cpp/Views/ioexpdmsdlg.cpp)
|
||||
- [ioexpsptdlg.cpp](file://cpp/Views/ioexpsptdlg.cpp)
|
||||
- [ioexpdlg.h](file://h/ioexpdlg.h)
|
||||
- [ioexpdmsdlg.h](file://h/ioexpdmsdlg.h)
|
||||
- [ioexpsptdlg.h](file://h/ioexpsptdlg.h)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [引言](#引言)
|
||||
2. [核心组件分析](#核心组件分析)
|
||||
3. [数据导出格式与数据结构映射](#数据导出格式与数据结构映射)
|
||||
4. [Excel导出功能实现](#excel导出功能实现)
|
||||
5. [用户自定义导出选项处理](#用户自定义导出选项处理)
|
||||
6. [导出过程中的进度反馈与错误处理](#导出过程中的进度反馈与错误处理)
|
||||
7. [大文件生成的内存优化方案](#大文件生成的内存优化方案)
|
||||
|
||||
## 引言
|
||||
本文档旨在全面文档化Geomative Studio软件中测试数据导出功能的实现。该功能主要由`CTdManager`和`CIOManager`两个核心管理类协同工作,支持将测试数据导出为Excel、CSV、TXT、URF等多种格式。文档将详细阐述其技术细节,包括不同格式的数据结构映射规则、用户自定义选项的处理逻辑、Excel导出中`excel.cpp`类库的使用流程,以及导出过程中的进度反馈、错误处理和内存优化策略。
|
||||
|
||||
## 核心组件分析
|
||||
|
||||
`CTdManager`和`CIOManager`是实现数据导出功能的两个核心类。
|
||||
|
||||
`CTdManager`类(位于`cpp/Managers/TdManager.cpp`)是测试数据的管理核心。它负责从数据库中获取测试数据,并提供将数据保存为特定文件格式的接口。例如,`CRsp2DTd`和`CRspCETd`等具体的数据类型类继承自`CTestingData`,并实现了`SaveTdToExcelFile`和`SaveTdToCsvFile`等方法,这些方法定义了如何将特定类型的数据组织并写入文件。
|
||||
|
||||
`CIOManager`类(位于`cpp/Managers/IOManager.cpp`)则负责更高层次的导出流程控制。其`Export`方法启动导出流程,创建一个导出对话框(`CIOExpDlg`),用户可以在其中选择要导出的项目、测区和具体的测试数据。`CIOManager`根据用户的选择,调用`CTdManager`提供的接口来执行实际的数据导出操作。
|
||||
|
||||
**Section sources**
|
||||
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
|
||||
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
|
||||
- [TdManager.h](file://h/TdManager.h)
|
||||
- [IOManager.h](file://h/IOManager.h)
|
||||
|
||||
## 数据导出格式与数据结构映射
|
||||
|
||||
系统支持将测试数据导出为四种主要格式:Excel、CSV、TXT和URF。每种格式都有其特定的数据结构映射规则。
|
||||
|
||||
对于**Excel和CSV**格式,数据通常被组织成多个工作表或数据块。以`CRsp2DTd`类为例,其`SaveTdToExcelFile`方法会创建一个Excel工作簿,并包含三个工作表:
|
||||
1. **Head (头部信息)**: 包含测试任务的元数据,如任务名称、位置、日期、设备信息等。
|
||||
2. **DAT (数据信息)**: 包含核心的测量数据,如电极配置(A, B, M, N)、视电阻率(Ro)、电压(V)、电流(I)等。
|
||||
3. **GR (接地电阻)**: 包含各电极的接地电阻测量值。
|
||||
|
||||
**TXT**格式的导出由`COperTxtFile`类(位于`cpp/Tools/OperTxtFile.cpp`)处理。该类提供了一个可配置的文本文件写入器,通过`SetParamWidth`方法设置每列的宽度,并使用`WriteFileContent`方法将字符串数组按固定宽度写入文件,确保数据在文本编辑器中对齐。
|
||||
|
||||
**URF**(Universal Resistivity data File)是一种专用于电阻率数据的通用格式。其导出由`COperUrfFile`类(位于`cpp/Tools/OperUrfFile.cpp`)负责。URF文件的结构包括一个头部注释,然后是电极坐标信息,最后是测量数据。`COperUrfFile`类提供了针对不同电极阵列(如温纳装置、施伦贝谢装置、跨孔装置等)生成电极坐标的专用方法,如`WriteElecByWenSch`和`WriteElecByCrossHoleGeomative`,确保导出的URF文件符合特定的地质勘探软件要求。
|
||||
|
||||
**Section sources**
|
||||
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
|
||||
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
|
||||
- [Rsp2DTd.cpp](file://cpp/ProblemZone/Rsp2DTd.cpp)
|
||||
- [RspCETd.cpp](file://cpp/ProblemZone/RspCETd.cpp)
|
||||
- [OperTxtFile.h](file://h/OperTxtFile.h)
|
||||
- [OperUrfFile.h](file://h/OperUrfFile.h)
|
||||
|
||||
## Excel导出功能实现
|
||||
|
||||
Excel导出功能的核心是`excel.cpp`和`excel.h`文件。这两个文件是通过Visual C++的ClassWizard工具从Microsoft Excel的类型库生成的C++包装类,它们提供了对Excel应用程序对象模型的COM接口访问。
|
||||
|
||||
导出过程遵循以下操作流程:
|
||||
|
||||
1. **创建Excel应用实例**:
|
||||
```cpp
|
||||
_Application* pComApp = new _Application;
|
||||
```
|
||||
这行代码创建了一个Excel应用程序的COM对象实例。
|
||||
|
||||
2. **创建和获取工作簿与工作表**:
|
||||
```cpp
|
||||
Workbooks comBooks;
|
||||
_Workbook comBook;
|
||||
Sheets comSheets;
|
||||
_Worksheet comSheet01;
|
||||
```
|
||||
通过`_Application`对象,可以获取`Workbooks`集合,进而创建一个新的工作簿(`comBook`),并从工作簿中获取`Sheets`集合来操作具体的工作表。
|
||||
|
||||
3. **创建工作表并命名**:
|
||||
```cpp
|
||||
comSheet01 = comSheets.GetItem(COleVariant((short)1));
|
||||
comSheet01.SetName(_T("Head"));
|
||||
```
|
||||
使用`GetItem`方法获取第一个工作表,并使用`SetName`方法将其重命名为"Head"。
|
||||
|
||||
4. **写入数据**:
|
||||
具体的数据写入逻辑由`CTestingData`的派生类(如`CRsp2DTd`)实现。这些类会调用`SaveTdHeadToExcelFile`等方法,通过遍历数据库记录集(`_RecordsetPtr`),并将数据逐行写入到`_Worksheet`对象的单元格中。
|
||||
|
||||
5. **应用样式和公式**:
|
||||
虽然在提供的代码片段中未直接体现,但`_Worksheet`和`Range`对象提供了丰富的属性和方法来设置单元格格式(如字体、颜色、边框)和应用公式。例如,可以通过`GetRange`方法获取一个单元格区域,然后设置其`NumberFormat`属性来定义数字显示格式。
|
||||
|
||||
6. **保存并清理**:
|
||||
```cpp
|
||||
comBook.SaveAs(COleVariant(f_szFileName), covOptional, ...);
|
||||
...
|
||||
pComApp->Quit();
|
||||
delete pComApp;
|
||||
```
|
||||
使用`SaveAs`方法将工作簿保存到指定路径。最后,必须显式调用`Quit`方法退出Excel应用,并释放所有COM对象指针,以避免内存泄漏。
|
||||
|
||||
**Section sources**
|
||||
- [excel.cpp](file://cpp/Tools/excel.cpp)
|
||||
- [excel.h](file://h/excel.h)
|
||||
- [Rsp2DTd.cpp](file://cpp/ProblemZone/Rsp2DTd.cpp)
|
||||
- [RspCETd.cpp](file://cpp/ProblemZone/RspCETd.cpp)
|
||||
|
||||
## 用户自定义导出选项处理
|
||||
|
||||
用户自定义导出选项主要通过导出对话框(`CIOExpDlg`)来处理。该对话框由`CIOManager`在`Export`方法中创建。
|
||||
|
||||
1. **字段选择**:
|
||||
对话框中的树形控件(`CTreeCtrl`)允许用户通过复选框选择要导出的具体项目、测区和测试数据。`CIOManager`通过遍历树形控件,检查每个节点的选中状态,来确定最终需要导出的数据集。
|
||||
|
||||
2. **时间范围和单位系统**:
|
||||
在提供的代码中,时间范围和单位系统的处理逻辑并未直接体现。这些选项很可能在`CTestingData`类的`SaveTdTo...File`方法内部实现。当从数据库查询数据时,会根据用户在UI中选择的时间范围构建SQL查询语句的`WHERE`子句。单位系统(如米/英尺)的转换则可能在数据写入文件之前,在内存中对数值进行换算。
|
||||
|
||||
**Section sources**
|
||||
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
|
||||
- [ioexpdlg.cpp](file://cpp/Views/ioexpdlg.cpp)
|
||||
- [ioexpdlg.h](file://h/ioexpdlg.h)
|
||||
|
||||
## 导出过程中的进度反馈与错误处理
|
||||
|
||||
### 进度反馈
|
||||
在提供的代码中,导出过程是同步执行的,没有明确的进度条或百分比反馈机制。整个过程在用户点击“确定”后,直到完成或出错才会返回控制权。更完善的实现可能需要在`CIOManager`或`CTdManager`中引入后台线程,并通过Windows消息或回调函数向UI发送进度更新。
|
||||
|
||||
### 错误处理
|
||||
系统采用了多层次的错误处理策略:
|
||||
1. **文件操作错误**: 在打开或写入文件时,会检查返回值(如`fopen`是否返回`NULL`)。如果失败,会通过`AfxMessageBox`或`MessageBoxEx`向用户显示错误信息,包括错误代码(`GetLastError()`)。
|
||||
2. **数据库操作错误**: 使用`try-catch`块捕获`_com_error`异常,当执行数据库查询或操作失败时,会弹出错误对话框。
|
||||
3. **逻辑错误**: 在执行关键操作前进行参数验证。例如,`COperTxtFile::SetParamWidth`会检查输入的宽度是否在有效范围内(6-50),否则会提示错误。
|
||||
4. **COM接口错误**: 在使用`excel.cpp`进行Excel操作时,虽然代码中没有显式捕获异常,但应假设`_Application`等对象的方法调用可能失败,需要进行返回值检查。
|
||||
|
||||
**Section sources**
|
||||
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
|
||||
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
|
||||
- [Rsp2DTd.cpp](file://cpp/ProblemZone/Rsp2DTd.cpp)
|
||||
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
|
||||
|
||||
## 大文件生成的内存优化方案
|
||||
|
||||
对于大文件的生成,系统主要通过以下方式优化内存使用:
|
||||
1. **流式写入 (Streaming)**: 所有文件导出操作都采用流式写入。无论是TXT、CSV还是URF文件,代码都是在打开文件后,一边从数据库读取记录,一边立即写入文件流(`fwrite`),然后立即处理下一条记录。这种方式避免了将整个数据集加载到内存中,从而将内存占用保持在较低水平。
|
||||
2. **分块处理**: 数据库查询使用`_RecordsetPtr`,它本质上是一个游标,允许逐行遍历结果集,而不是一次性将所有数据加载到内存。
|
||||
3. **及时释放资源**: 在操作完成后,代码会显式关闭文件句柄(`fclose`)、关闭数据库记录集(`Close()`)并释放COM对象(`ReleaseDispatch()`),确保资源被及时回收。
|
||||
|
||||
**Section sources**
|
||||
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
|
||||
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
|
||||
- [Rsp2DTd.cpp](file://cpp/ProblemZone/Rsp2DTd.cpp)
|
||||
Reference in New Issue
Block a user