1. 流类型通常都支持对流中数据的随机访问。
可以重定位流, 使之跳过一些数据, 首先读取最后一行, 然后读取第一行, 依此类推。
1.1 标准厍提供了一对函数, 来定位( seek )到流中给定的位置, 以及告诉( tell) 我们当前位置
- seek函数:将标记 seek 到一个给定位置来重定位它;
- tell 函数:tell 我们标记的当前位置。
标准库实际上定义了两对 seek 和 tell 函数:
- g 版本表示我们正在“ 获得”( 读取) 数据
- p 版本表示我们正在“ 放置”( 写入) 数据
只适用于fstream和sstream。
操作 | 解释 |
---|
tellg() | tellp 返回一个输入流中(tellg)或输出流中(tellp)标记的当前位置。 | seekg(pos) | seekp(pos) 在一个输入流或输出流中将标记重定位到给定的绝对地址。pos通常是一个当前teelg或tellp返回的值。 | seekp(off, from) seekg(off, from) | 在一个输入流或输出流中将标记定位到from之前或之后off个字符,from可以是下列值之一:beg,偏移量相对于流开始位置;cur,偏移量相对于流当前位置;end,偏移量相对于流结尾位置。 |
1.2 只有一个标记
标准库区分 seek 和 tell 函数的“ 放置” 和“ 获得” 版本这一特性可能会导致误解。 即使标准库进行了区分, 但它在一个流中只维护单一的标记—并不存在独立的读标记和写标记
由于只有单一的标记, 因此只要我们在读写操作间切换, 就必须进行 seek 操作来重1定位标记。 .
1.3 重定位标记
seek 函数有两个版本: 一个移动到文件中的“ 绝对” 地址: 另一个移动到一个给定位置的指定偏移量:
seekg (new_position); / / 将读标记移动到指定的 pos_type 类型的位置
seekp (new_position); / / 将写标记移动到指定的 pos_type 类型的位置
/ / 移动到给定起始点之前或之后指定的偏移位置
seekg (offset, from); / / 将读标记移动到距 from 偏移量为 offset 的位置
seekp (offset, from); / / 将写标记移动到距 from 偏移量为 of fset 的位置
- pos_type表示一个文件位置
- off_type 表示距当前位置的一个偏移量。
一个 off_type 类型的值可以是正的也可以是负品, 即可以在文件中向前移动或向后移动。
1.4 访问标记
函数 tellg 和 tellp 返回一个pos_type表示流的当前位置。tell 函数通常用来记住一个位置, 以便稍后再定位回来
ostringstream::writeStr;
ostringstream::pos_type mark = writeStr.tellp ( );
if (cancelEntry)
/ / 回到刚才记住的位置
writeStr.seekp (mark);
/ / 以读写方式打开文件, 并定位到文件尾
fstream inOut("test_2.txt", fstream::ate|fstream::in|fstream::out);
if(!inOut){
return EXIT_FAILURE;
}
/ / inOut 以 ate 模式打开, 因此一开始就定义到其文件尾
auto end_mark = inOut.tellg();
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表示换行符
cout << line.size() << endl;
auto mark = inOut.tellg();/ / 记住读取位置
inOut.seekp(0,fstream::end);II 将写标记移动到文件尾
inOut << cnt;/ / 输出累计的长度
/ / 如果不是最后一行, 打印一个分隔符
if(mark != end_mark)
inOut << " ";
inOut.seekg(mark);/ / 恢复读位置
}
inOut.seekp(0,fstream::end);
原始文件:
abed
efg
hi
j
修改过的文件:
abed
efg
hi
j5
9 12 14
|