#ifndef __CSV_TABLE_HPP__ #define __CSV_TABLE_HPP__ #include #include #include #include namespace jdi { /** * @brief CSV 文件的解析结果,保存列名与**列优先**的数值矩阵。 * * 采用列优先(每条信号一整块连续内存)而不是行优先的二维数组,原因有二: * 1. 大型文件(百万行级)若按行存储会产生上百万次独立堆分配, * 每行还要额外承担 vector 的控制块与容量对齐开销,实测内存放大接近 1.5 倍; * 2. 后续构建信号时可以直接把整列**移动**进 SignalData,不再逐元素拷贝。 */ struct CsvTable { std::vector headers; /**< 列名(已去除引号与首尾空白)。 */ std::vector> columns; /**< 列优先数值矩阵:columns[列][行],缺失处为 NaN。 */ std::size_t rowCount = 0; /**< 有效数据行数。 */ wchar_t delimiter = L','; /**< 实际使用的分隔符。 */ unsigned long long fileBytes = 0; /**< 源文件字节数(用于按比例预留容量)。 */ /** * @brief 判断解析结果是否包含可用的表格数据。 * @return 存在列名且存在数据行时返回 true。 */ bool HasData() const { return !headers.empty() && (rowCount > 0); } }; /** * @brief 加载进度信息。 * * 解析阶段会携带真实的"已读 / 总字节数";列重组与统计阶段没有字节可计, * 此时 `hasBytes` 为 false,界面应只展示百分比。 */ struct CsvProgressInfo { double ratio = 0.0; /**< 0-1 总体完成比例。 */ unsigned long long bytesRead = 0; /**< 已读取字节数。 */ unsigned long long totalBytes = 0; /**< 文件总字节数。 */ bool hasBytes = false; /**< 上述字节数字段是否有效。 */ }; /** * @brief 解析进度回调。 * * 在解析过程中按块回调;返回 false 表示请求取消,解析会尽快停止并返回失败。 */ using CsvProgress = std::function; /** * @brief 读取并解析一个 CSV 文件。 * * 文件以分块流式方式读取(不把整个文件一次性读入内存), * 因此内存占用只与解析结果相关,不会因文件体积成倍放大,也没有体积上限。 * * @param [IN] filePath CSV 文件完整路径(宽字符,支持中文路径)。 * @param [OUT] table 解析结果输出。 * @param [OUT] error 失败原因描述(成功时清空)。 * @param [IN] progress 解析进度回调,可为空。 * @return 解析成功返回 true,否则返回 false。 */ bool LoadCsvTable(const std::wstring& filePath, CsvTable& table, std::wstring& error, const CsvProgress& progress = CsvProgress()); } // namespace jdi #endif // __CSV_TABLE_HPP__