# 数据导出与导入 **本文档引用的文件** - [ioexpdlg.cpp](file://cpp/Views/ioexpdlg.cpp) - [ioexpdmsdlg.cpp](file://cpp/Views/ioexpdmsdlg.cpp) - [ioexpsptdlg.cpp](file://cpp/Views/ioexpsptdlg.cpp) - [IOManager.cpp](file://cpp/Managers/IOManager.cpp) - [DialMeasureData.cpp](file://cpp/Views/DialMeasureData.cpp) - [DownloadDataProgressDlg.cpp](file://cpp/Views/DownloadDataProgressDlg.cpp) - [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp) - [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp) - [excel.cpp](file://cpp/Tools/excel.cpp) - [ioexpdlg.h](file://h/ioexpdlg.h) - [ioexpdmsdlg.h](file://h/ioexpdmsdlg.h) - [ioexpsptdlg.h](file://h/ioexpsptdlg.h) ## 目录 1. [引言](#引言) 2. [数据导出功能架构](#数据导出功能架构) 3. [导出对话框与用户交互](#导出对话框与用户交互) 4. [IOManager协调机制](#iomanager协调机制) 5. [文件操作工具实现](#文件操作工具实现) 6. [导出流程与进度反馈](#导出流程与进度反馈) 7. [用户操作指南](#用户操作指南) 8. [开发者扩展指南](#开发者扩展指南) 9. [结论](#结论) ## 引言 Geomative Studio软件提供了一套完整的数据导出与导入功能,旨在支持地质勘探数据在不同格式间的转换与共享。本系统化文档详细说明了`ioexpdlg`、`ioexpdmsdlg`和`ioexpsptdlg`三个核心对话框所支持的导出格式(包括Excel、CSV、TXT、URF)及其底层实现逻辑。文档深入解析了`IOManager`如何作为中央协调者,调用`OperTxtFile`、`OperUrfFile`和`excel`等专用文件操作工具来完成复杂的数据转换与文件生成任务。 此外,本文档阐述了从`DialMeasureData`对话框触发的完整导出流程,以及`DownloadDataProgressDlg`提供的实时进度反馈机制。为最终用户提供了关于如何选择导出范围、配置文件命名规则和验证导出完整性的详细操作说明。同时,为开发者提供了关于如何扩展支持新的导出格式(如JSON、PDF)、优化大数据量导出性能的缓冲策略,以及处理文件编码、跨平台换行符等兼容性问题的最佳实践。 **Section sources** - [ioexpdlg.cpp](file://cpp/Views/ioexpdlg.cpp#L1-L244) - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1-L2064) ## 数据导出功能架构 Geomative Studio的数据导出功能采用分层架构设计,由用户界面层、业务逻辑层和数据访问层协同工作。核心组件`IOManager`位于业务逻辑层,负责协调整个导出流程。当用户通过`DialMeasureData`等界面组件发起导出请求时,控制权会传递给`IOManager`。 `IOManager`首先通过`CIOExpDlg`对话框收集用户的导出选项,包括选择要导出的项目、测区和测点数据。随后,它根据用户的选择,调用相应的数据提取和转换逻辑。对于数据库导出,`IOManager`使用ADOX库创建一个新的Access数据库文件(.accdb),并定义其表结构。然后,它将选定的数据从主数据库中提取出来,并插入到新创建的导出文件中。 对于其他格式(如TXT、URF、Excel),`IOManager`会实例化对应的文件操作工具类(如`OperTxtFile`、`OperUrfFile`、`excel`),并将数据流传递给它们进行格式化和写入。这种设计实现了关注点分离,使得`IOManager`可以专注于流程控制,而具体的文件格式实现则由专门的工具类负责。 ```mermaid graph TD A[用户界面] --> B[IOManager] B --> C[数据提取] C --> D[格式转换] D --> E[文件生成] E --> F[导出文件] B --> G[OperTxtFile] B --> H[OperUrfFile] B --> I[excel] G --> E H --> E I --> E ``` **Diagram sources ** - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L35-L98) - [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp#L19-L35) - [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp#L19-L29) - [excel.cpp](file://cpp/Tools/excel.cpp#L1-L800) **Section sources** - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L35-L98) - [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp#L19-L35) - [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp#L19-L29) - [excel.cpp](file://cpp/Tools/excel.cpp#L1-L800) ## 导出对话框与用户交互 数据导出功能通过一系列对话框与用户进行交互,其中`CIOExpDlg`是主对话框,它整合了`CIOExpDmsDlg`和`CIOExpSptDlg`两个子对话框,分别用于选择数据(项目、测区、测点)和脚本。 ### CIOExpDlg 主对话框 `CIOExpDlg`继承自`CDialog`,其主要职责是提供一个选项卡式界面,让用户在“数据”和“脚本”两个选项卡之间切换。当用户点击“确定”按钮时,该对话框会检查用户是否在任一选项卡中选择了要导出的项目。如果未选择任何项目,会弹出提示框要求用户选择。如果选择了项目,则会弹出文件保存对话框,让用户指定导出文件的路径和名称(默认为.accdb格式)。 ```mermaid classDiagram class CIOExpDlg { +CString m_szFileName +CIOExpDmsDlg m_ioDmsDlg +CIOExpSptDlg m_ioSptDlg -INT_PTR* m_pRet +CIOExpDlg(CWnd* pParent) +CIOExpDlg(INT_PTR* pRet, CWnd* pParent) +virtual BOOL Create(UINT nID, CWnd* pParentWnd) +virtual void OnOK() +virtual void OnCancel() +virtual BOOL OnInitDialog() +afx_msg void OnSelchangeIoExpTab(NMHDR* pNMHDR, LRESULT* pResult) } class CIOExpDmsDlg { +CTreeCtrl m_dmsTree +CIOExpDmsDlg(CWnd* pParent) +virtual BOOL OnInitDialog() +afx_msg void OnShowWindow(BOOL bShow, UINT nStatus) +afx_msg void OnClickTreeExpDms(NMHDR* pNMHDR, LRESULT* pResult) +afx_msg void OnSelchangingTreeExpDms(NMHDR* pNMHDR, LRESULT* pResult) } class CIOExpSptDlg { +CListCtrl m_sptList +CIOExpSptDlg(CWnd* pParent) +virtual BOOL OnInitDialog() +afx_msg void OnShowWindow(BOOL bShow, UINT nStatus) } CIOExpDlg --> CIOExpDmsDlg : "包含" CIOExpDlg --> CIOExpSptDlg : "包含" ``` **Diagram sources ** - [ioexpdlg.h](file://h/ioexpdlg.h#L16-L56) - [ioexpdmsdlg.h](file://h/ioexpdmsdlg.h#L13-L44) - [ioexpsptdlg.h](file://h/ioexpsptdlg.h#L13-L42) ### CIOExpDmsDlg 数据选择对话框 `CIOExpDmsDlg`使用一个`CTreeCtrl`(树形控件)来展示项目、测区和测点的层级结构。用户可以通过点击树节点旁的复选框来选择要导出的数据。该对话框在初始化时会设置树形控件的样式,使其显示连接线和按钮。`OnClickTreeExpDms`消息处理函数实现了智能的复选框逻辑:当用户选中一个父节点时,其所有子节点也会被自动选中;当用户取消选中一个父节点时,其所有子节点也会被取消选中。 ### CIOExpSptDlg 脚本选择对话框 `CIOExpSptDlg`使用一个`CListCtrl`(列表控件)来展示所有可用的脚本。该控件被配置为支持全行选择、拖拽列头、网格线和复选框。在`OnInitDialog`函数中,它会动态地从资源文件中加载列标题(如“脚本编号”、“脚本名称”、“电极数量”等),并创建相应的列。 **Section sources** - [ioexpdlg.cpp](file://cpp/Views/ioexpdlg.cpp#L1-L244) - [ioexpdmsdlg.cpp](file://cpp/Views/ioexpdmsdlg.cpp#L1-L145) - [ioexpsptdlg.cpp](file://cpp/Views/ioexpsptdlg.cpp#L1-L115) - [ioexpdlg.h](file://h/ioexpdlg.h#L1-L62) - [ioexpdmsdlg.h](file://h/ioexpdmsdlg.h#L1-L50) - [ioexpsptdlg.h](file://h/ioexpsptdlg.h#L1-L48) ## IOManager协调机制 `IOManager`是整个数据导出功能的核心协调者。它通过`Export`方法启动导出流程。该方法首先创建并显示`CIOExpDlg`对话框,等待用户完成选择。一旦用户确认,`IOManager`会根据用户选择的文件路径,调用`CreateExpDatabase`方法创建一个新的Access数据库文件,并定义其表结构(如project、tz、td等)。 ```mermaid sequenceDiagram participant User as 用户 participant CIOExpDlg as CIOExpDlg participant IOManager as IOManager participant Database as 数据库 participant File as 文件系统 User->>CIOExpDlg : 点击“导出” CIOExpDlg->>CIOExpDlg : 显示对话框 User->>CIOExpDlg : 选择数据并点击“确定” CIOExpDlg->>IOManager : 返回文件路径 IOManager->>IOManager : 创建导出数据库 IOManager->>Database : 提取选定数据 Database-->>IOManager : 返回数据 IOManager->>File : 写入数据到.accdb文件 File-->>IOManager : 写入完成 IOManager-->>User : 显示成功消息 ``` **Diagram sources ** - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L35-L98) - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L206-L656) **Section sources** - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L35-L98) ## 文件操作工具实现 ### OperTxtFile 文本文件操作 `OperTxtFile`类负责将数据导出为纯文本(TXT)格式。它提供了一个`SetParamWidth`方法来设置每个字段的宽度,确保导出的文本文件具有整齐的列对齐。`OpenFileforWrite`方法用于打开或创建一个文本文件。`WriteFileContent`方法接收一个`CStringArray`,将数组中的每个字符串按照设定的宽度填充空格后写入文件,不足宽度的部分用空格补齐,每个数组元素写入后会自动添加换行符。 ### OperUrfFile URF文件操作 `OperUrfFile`类专门用于生成通用电阻率数据文件(URF)。它支持多种电极阵列类型,如温纳-施伦贝谢(Wenner-Schlumberger)、跨孔(Cross-Hole)等。`WriteElecByAR`方法是核心,它根据传入的阵列类型(iAR)参数,调用不同的私有方法(如`WriteElecByWenSch`、`WriteElecByCrossHole`)来生成符合特定阵列几何形状的电极坐标。URF文件的头部包含固定的注释和单位信息。 ### Excel 文件操作 `excel.cpp`文件包含通过MFC的`COleDispatchDriver`包装类与Microsoft Excel应用程序进行交互的代码。这些包装类(如`_Application`、`_Workbook`、`_Worksheet`)允许程序以自动化的方式创建Excel工作簿、写入数据、设置单元格格式等。虽然具体的导出逻辑未在提供的代码片段中完全展示,但可以推断`IOManager`会使用这些类来将数据写入Excel的单元格中,并生成.xlsx或.xls文件。 **Section sources** - [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp#L1-L166) - [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp#L1-L800) - [excel.cpp](file://cpp/Tools/excel.cpp#L1-L800) ## 导出流程与进度反馈 ### 从DialMeasureData触发导出 数据导出流程通常从`DialMeasureData`对话框开始,该对话框是用户进行测量操作的主要界面。当用户完成测量并希望导出数据时,可以通过菜单或按钮触发导出功能。`DialMeasureData`类本身不直接处理导出,而是通过调用`IOManager`的`Export`方法来启动整个流程。 ### DownloadDataProgressDlg 进度反馈 在执行耗时较长的导出或导入操作时,系统会显示`DownloadDataProgressDlg`对话框来提供进度反馈。该对话框在初始化时会启动一个工作线程(`DownloadThread`或`UploadThread`),以避免阻塞主UI线程。工作线程会定期调用`ShowProcessPercent`方法,该方法根据已完成的工作量计算百分比,并更新对话框上的进度标签。这确保了用户界面的响应性,并让用户清楚地了解操作的进展情况。 **Section sources** - [DialMeasureData.cpp](file://cpp/Views/DialMeasureData.cpp#L1-L800) - [DownloadDataProgressDlg.cpp](file://cpp/Views/DownloadDataProgressDlg.cpp#L1-L479) ## 用户操作指南 ### 选择导出范围 1. 在软件主界面,导航到需要导出数据的项目。 2. 右键点击项目、测区或测点,选择“导出”选项。 3. 在弹出的“数据导出”对话框中,切换到“数据”选项卡。 4. 在树形结构中,勾选您想要导出的项目、测区和测点。勾选父节点会自动包含其所有子节点。 5. 切换到“脚本”选项卡,勾选您想要导出的脚本。 ### 配置文件命名规则 1. 完成选择后,点击“确定”。 2. 系统会弹出“另存为”对话框。 3. 在“文件名”输入框中,输入您希望的文件名。 4. 系统默认的文件扩展名为`.accdb`,您也可以选择其他格式(如果功能支持)。 5. 选择保存位置,然后点击“保存”。 ### 验证导出完整性 1. 导出完成后,系统会显示“导出成功”的提示。 2. 前往您指定的保存位置,找到导出的文件。 3. 打开文件(例如,用Access打开.accdb文件,用文本编辑器打开.txt文件)。 4. 检查文件内容是否与您在导出对话框中选择的数据范围一致,确保所有必要的数据都已包含在内。 ## 开发者扩展指南 ### 新增导出格式(如JSON、PDF) 要支持新的导出格式,开发者需要遵循以下步骤: 1. **创建新的工具类**:创建一个名为`OperJsonFile`或`OperPdfFile`的新类,类似于`OperTxtFile`和`OperUrfFile`。 2. **实现核心方法**:在新类中实现`OpenFile`、`WriteData`和`CloseFile`等核心方法。对于JSON,可以使用第三方库(如nlohmann/json)来构建和序列化JSON对象。对于PDF,可以使用库(如libHaru或PoDoFo)来创建PDF文档并写入表格数据。 3. **扩展IOManager**:在`IOManager`类中添加新的导出方法(如`ExportToJSON`、`ExportToPDF`),并在`Export`方法中根据用户选择的格式调用相应的方法。 4. **更新用户界面**:在“另存为”对话框的文件类型过滤器中添加新的格式选项(如`JSON Files (*.json)|*.json||`)。 ### 优化大数据量导出性能 对于大数据量的导出,应采用缓冲和分块处理策略: 1. **分批读取**:不要一次性将所有数据加载到内存中。使用数据库的分页查询(如`LIMIT`和`OFFSET`)或游标,分批读取数据。 2. **缓冲写入**:在文件操作工具中,使用缓冲区(buffer)来累积一定量的数据后再写入磁盘,减少I/O操作次数。 3. **异步处理**:将导出操作放在后台线程中执行,避免阻塞UI。`DownloadDataProgressDlg`的实现已经展示了如何使用`AfxBeginThread`来实现这一点。 ### 处理兼容性问题 1. **文件编码**:对于文本文件(TXT、CSV),应明确指定编码格式(如UTF-8)。在`OperTxtFile`中,可以修改`fopen`调用,使用`"w+, ccs=UTF-8"`来确保文件以UTF-8编码保存,避免中文乱码。 2. **跨平台换行符**:Windows使用`\r\n`,而Unix/Linux使用`\n`。在`OperTxtFile`的`WriteFileContent`方法中,可以根据目标平台动态选择换行符。可以通过编译宏(如`_WIN32`)来判断当前平台。 ## 结论 Geomative Studio的数据导出与导入功能通过清晰的分层架构和模块化设计,实现了高效、可靠的数据交换。`IOManager`作为核心协调者,有效地整合了用户界面、数据访问和文件生成等多个组件。通过分析`ioexpdlg`系列对话框和`OperTxtFile`、`OperUrfFile`等工具类,我们理解了系统如何支持多种导出格式并提供良好的用户体验。 本文档不仅为用户提供了清晰的操作指南,也为开发者指明了扩展和优化的方向。通过遵循本文档中的最佳实践,可以确保新功能的顺利集成,并持续提升软件在处理复杂地质数据方面的专业性和可靠性。