各种流类型通常都支持对流中数据的随机访问。但绝大多数系统中绑定到 cin、cout、cerr、clog 的流不支持随机访问。
seek 和 tell 函数
函数 | 说明 |
---|---|
tellg | 返回输入流中标记的当前位置 |
tellp | 返回输出流中标记的当前位置 |
seekg(pos) | 在一个输入流中将标记重定位到给定的绝对地址 |
seekp(pos) | 在一个输出流中将标记重定位到给定的绝对地址 |
seekg(off,from) | 在一个输入流中将标记重定位到给定 from 的偏移量为 offset 的位置 |
seekp(off,from) | 在一个输出流中将标记重定位到给定 from 的偏移量为 offset 的位置 |
上面 from 的取值可以是:
- beg,偏移量相对于流开始位置。
- cur,偏移量相对于流当前位置。
- end,偏移量相对于流结尾位置。
注意:
- g 版本用于读取的数据,理论上来讲只能对 istream 和派生自 istream 的类型 ifstream 和 istringstream 使用 g 版本。
- p 版本用于写入的数据,理论上来讲对 ostream 和派生自 ostream 的类型 ofstream 和 ostringstream 使用 p 版本。
- fstream 和 stringstream 既能读又能写,因此这些类型既可以使用 g 版本也可以使用 p 版本。
只有一个标记
标记只有一个,并不存在独立的读标记和独立的写标记。
重定位标记
- pos 的类型是 pos_type,表示一个文件位置。
- offset 的类型是 off_type,表示一个偏移量,可以是正的也可以是负的,表示向前、向后移动。
读写同一个文件
int main(void)
{
fstream inOut("test.txt", fstream::ate | fstream::in | fstream::out);
if (!inOut)
{
cerr << "Unable to open file" << endl;
return EXIT_FAILURE;
}
auto end_mark = inOut.tellg(); //@ ate 模式打开,因此是文件末尾位置
inOut.seekg(0, fstream::beg); //@ 重定位到文件首位置
size_t cnt = 0;
string line;
while (inOut && inOut.tellg() != end_mark && getline(inOut, line))
{
cnt += line.size() + 1; //@ +1 表示换行符
auto mark = inOut.tellg(); //@ 记录当前的读取位置
inOut.seekp(0,fstream::end); //@ 写指针移动到文件尾
inOut << cnt; //@ 写入累计长度
if (mark != end_mark) inOut << " ";
inOut.seekg(mark); //@ 恢复到读位置
}
inOut.seekp(0, fstream::end); //@ 定位到文件尾
inOut << "
"; //@ 在文件尾输出一个换行符
return 0;
}
test.txt 原来的内容:
abcd
efj
hi
j
修改后的内容:
abcd
efj
hi
j
5 9 12 14