C++循环读写二进制点云文件时第二次读取报错排查
二进制点云文件读写故障排查
相关代码说明
两个类成员函数共同操作同一C:\PointCloud.dat二进制文件,配合三层嵌套循环实现点云按索引读取、计算处理、回写的逻辑,相关代码如下:
Reading(按索引读点)函数
负责根据i、j、k索引读取文件中存储的point3d类型点云数据:
myRepositoryPointCloud::point3d myRepositoryPointCloud::Reading(int i, int j, int k) { ifstream rf("C:\\PointCloud.dat", ios::out | ios::binary); if (!rf) { cout << "Cannot open file!" << endl; } point3d resultPt; rf.seekg((i * GetCntPointY() * GetCntPointZ() + j * GetCntPointZ() + k) * sizeof(point3d)); rf.read((char *)&resultPt, sizeof(point3d)); rf.close(); if (!rf.good()) { cout << "Error occurred at reading time!" << endl; } return resultPt; }
Writing(按索引写点)函数
负责将point3d类型点云数据写入文件对应i、j、k索引位置:
void myRepositoryPointCloud::Writing(int i, int j, int k, point3d & APoint) { ofstream wf("C:\\PointCloud.dat", ios::out | ios::binary); if (!wf) { cout << "Cannot open file!" << endl; } wf.seekp((i * GetCntPointY() * GetCntPointZ() + j * GetCntPointZ() + k) * sizeof(point3d)); wf.write((char *)&APoint, sizeof(point3d)); wf.close(); if (!wf.good()) { cout << "Error occurred at writing time!" << endl; } }
循环调用逻辑
三层嵌套循环中逐点读取、处理、回写,执行逻辑为:读取对应索引位置的点数据,经球体相交计算处理后,若点满足已删除或可见的判定条件,则将修改后的点写回文件原索引位置:
point3d CurrentPoint; for (int i = 0; i < EndPoint.i - StartPoint.i; i++) { for (int j = 0; j < EndPoint.j - StartPoint.j; j++) { for (int k = 0; k < EndPoint.k - StartPoint.k; k++) { CurrentPoint = FPointCloud->Reading(i, j, k); if (!CurrentPoint.deleted) { Sphere->CalcIntersectSphereToPoint(&CurrentPoint); if (CurrentPoint.deleted || CurrentPoint.visible) { FPointCloud->Writing(i, j, k, &CurrentPoint); } } } }
故障表现
- 循环执行到第二步时,Reading函数触发
Error occurred at reading time!读取错误 - 移除循环中对Writing函数的调用后,程序可正常运行
根因定位
核心故障原因是文件打开模式配置错误,附带其他逻辑问题:
- Writing函数截断原文件:使用
ofstream打开文件时仅指定ios::out | ios::binary,未搭配ios::in参数,该模式下打开已存在文件会直接将文件截断为0字节,清空所有原有数据。第一次写入单个点后,文件仅保留当前写入的点数据,其余位置内容全部丢失,下一次循环读取其他偏移位置时,文件长度不足,read操作无法读取到足够字节,触发流错误状态,抛出读取异常。 - Reading函数打开模式错误:作为读文件的输入流
ifstream,错误传入了写模式专用的ios::out参数,属于无效配置,会导致流打开行为不符合预期。 - 传参类型不匹配:Writing函数形参为
point3d类型引用,调用时传入了&CurrentPoint即point3d*指针类型,正常情况下会直接编译报错。 - 错误处理逻辑缺失:判断文件打开失败后仅打印日志,未提前返回,后续仍对无效流对象执行seek、读写操作,会触发未定义行为。
- (性能问题)每次读写单个点都重复执行打开、关闭文件操作,三层循环下IO开销极高,运行效率极低。
修复方案
- 修正Reading函数打开模式:读文件使用
ios::in | ios::binary,移除错误的ios::out参数,打开失败时直接返回默认值,避免后续无效操作。 - 修正Writing函数打开模式:需要随机覆盖写入、不破坏原有文件内容时,使用
ios::in | ios::out | ios::binary模式打开,该模式不会截断原有文件,可正常跳转到指定偏移位置写入数据。 - 修正Writing函数调用参数:传参时直接传入
CurrentPoint,不要取地址传指针,匹配引用形参类型。 - 优化错误处理:文件打开失败、读写失败时打印日志后立即返回,不要继续操作无效流。
- 可选性能优化:在循环开始前一次性打开读写文件流,整个循环执行完成后再关闭流,避免频繁开关文件的IO开销。
内容的提问来源于stack exchange,提问作者Andrey Angerchik
相关产品推荐
相关产品推荐

