diff --git a/src/io/gpr/IprbReader.cpp b/src/io/gpr/IprbReader.cpp index 4441753..180c63d 100644 --- a/src/io/gpr/IprbReader.cpp +++ b/src/io/gpr/IprbReader.cpp @@ -12,21 +12,28 @@ BScan readIprb(const std::string& path, const IprHeader& h) { throw std::runtime_error("readIprb: 无法打开文件: " + path); } - const std::streamsize fileSize = f.tellg(); - const std::int64_t traces = static_cast(h.lastTrace) + 1; - const std::int64_t count = static_cast(h.samples) * traces; - const std::int64_t expected = count * 2; - if (fileSize != expected) { - throw std::runtime_error("readIprb: 文件大小与 samples*traces*2 不符: " + path); + // 文件大小为权威:道数由实测字节数推导,而非 header 的 LAST TRACE。 + // 真实数据规律:实际道数 = LAST TRACE(非 LAST TRACE+1),故不能硬假设 +1。 + const std::int64_t fileBytes = static_cast(f.tellg()); + const std::int64_t samples = static_cast(h.samples); + if (samples <= 0) { + throw std::runtime_error("readIprb: samples 非法(<=0): " + path); } + const std::int64_t bytesPerTrace = samples * 2; // int16 + if (fileBytes % bytesPerTrace != 0) { + throw std::runtime_error( + "readIprb: 文件大小不是 samples*2 的整数倍: " + path); + } + const std::int64_t traces = fileBytes / bytesPerTrace; BScan b; b.samples = h.samples; b.traces = traces; - b.data.resize(static_cast(h.samples) * traces); + b.data.resize(static_cast(samples * traces)); f.seekg(0, std::ios::beg); - f.read(reinterpret_cast(b.data.data()), static_cast(expected)); + f.read(reinterpret_cast(b.data.data()), + static_cast(fileBytes)); if (!f) { throw std::runtime_error("readIprb: 读取数据失败: " + path); } diff --git a/src/io/gpr/IprbReader.hpp b/src/io/gpr/IprbReader.hpp index c6edc29..d57dd69 100644 --- a/src/io/gpr/IprbReader.hpp +++ b/src/io/gpr/IprbReader.hpp @@ -16,8 +16,9 @@ struct BScan { std::vector data; // 大小 = samples*traces }; -// 读取 .iprb 二进制 B-scan:traces = h.lastTrace+1; -// 校验 samples*traces*2 == 文件字节数,不符抛 std::runtime_error;文件打不开抛 std::runtime_error。 +// 读取 .iprb 二进制 B-scan:以文件大小为权威,traces = fileBytes / (samples*2)。 +// 要求 fileBytes 是 samples*2 的整数倍,否则抛 std::runtime_error;文件打不开抛 std::runtime_error。 +// 注意:h.lastTrace 仅作 header 提示,不决定道数(真实数据规律为道数==lastTrace,非 +1)。 BScan readIprb(const std::string& path, const IprHeader& h); } // namespace geopro::io::gpr diff --git a/tests/io/gpr/test_iprb_reader.cpp b/tests/io/gpr/test_iprb_reader.cpp index 7d2cbbe..afe96e3 100644 --- a/tests/io/gpr/test_iprb_reader.cpp +++ b/tests/io/gpr/test_iprb_reader.cpp @@ -25,12 +25,24 @@ TEST(IprbReader, ReadsInt16AndLayout) { std::remove(path.c_str()); } TEST(IprbReader, ThrowsOnSizeMismatch) { - std::vector raw{0,1,2,3,4}; // 5 个,与 samples*traces 不符 + std::vector raw{0,1,2,3,4}; // 5 个,非 samples 整数倍 → 抛 auto path = writeTmp(raw); - IprHeader h{}; h.samples = 3; h.lastTrace = 3; // 期望 12 + IprHeader h{}; h.samples = 3; h.lastTrace = 3; // 5*2=10, 10%6!=0 EXPECT_THROW(readIprb(path, h), std::runtime_error); std::remove(path.c_str()); } +// 真实数据规律:LAST TRACE=N 但文件恰含 N 道(非 N+1)。 +// 文件大小为权威 → traces 应等于文件实含道数 N,而非 N+1。 +TEST(IprbReader, FileSizeIsAuthoritativeNotLastTracePlusOne) { + // 4 道×3 采样 = 12 个 int16,文件恰含 4 道。 + std::vector raw{0,1,2, 10,11,12, 20,21,22, 30,31,32}; + auto path = writeTmp(raw); + IprHeader h{}; h.samples = 3; h.lastTrace = 4; // 假设 +1 会得 5 道(错) + auto b = readIprb(path, h); + EXPECT_EQ(b.traces, 4); // 以文件大小为准 → 4,复刻真实数据 traces==lastTrace 规律 + EXPECT_EQ(b.data.size(), 12u); + std::remove(path.c_str()); +} TEST(IprbReader, ThrowsOnMissingFile) { IprHeader h{}; h.samples = 3; h.lastTrace = 3; EXPECT_THROW(readIprb("____no_such_file____.iprb", h), std::runtime_error);