能否用unget()将std::getline读取的整行放回istream?或有替代方法?
解决整行放回输入流的问题
首先明确:std::unget()确实只能回退单个字符,没法直接把整行放回输入流——因为std::getline已经把整行(包括末尾的换行符)从流的缓冲区里提取出来了,流的读指针已经移动到了这行之后的位置。
给你几个实用的解决方案:
方案1:记录行起始位置,用seekg回退(适用于可随机访问的流,比如文件流)
在调用getline之前,先记录当前流的位置,一旦发现行格式错误,就用seekg回到这个起始位置。这种方法简单直接,适合文件这类支持随机访问的输入流:
std::streampos row_start; for (std::string row; row_start = is.tellg(), std::getline(is, row); ) // 先记录行起始位置,再读行 { if (std::ranges::count(row, ',') != Temp_reading::read_parameters - 1) { std::cerr << "Row: " << row << " contains wrong number of columns in csv file\n"; // 回退到行起始位置 if (is.seekg(row_start)) { is.clear(std::ios_base::failbit); // 设置失败位 } else { std::cerr << "Failed to seek back to row start\n"; // 处理seek失败的情况 } return; } // 处理格式正确的行 }
方案2:直接保存错误行,无需放回流
既然你已经把整行读到了row字符串里,完全可以直接保存这个错误行,后续需要处理的话直接使用这个字符串,没必要放回输入流。比如可以把错误行传递给上层逻辑,或者写入错误日志,这样比操作流更简单。
方案3:手动将整行写回流(通用但需注意细节)
如果你的流不支持随机访问(比如标准输入、网络流),可以手动把row加上换行符(因为getline会吃掉换行符)写回流中。不过要注意,输入流默认是只读的,需要先转为可读写模式,或者用流缓冲区操作:
// 先把getline吃掉的换行符加回去 row += '\n'; // 清除流的错误状态,确保可以操作 is.clear(); // 获取流的缓冲区,将字符串写回 std::streambuf* buf = is.rdbuf(); for (char c : row) { if (buf->sputbackc(c) == std::char_traits<char>::eof()) { std::cerr << "Failed to put character back\n"; break; } } // 设置失败位 is.clear(std::ios_base::failbit); return;
不过这个方法有局限性:不是所有流的缓冲区都支持sputbackc多次调用,如果流的缓冲区没有足够的回溯空间,会失败。
内容的提问来源于stack exchange,提问作者a_floating_point
相关产品推荐
相关产品推荐

