9,流的随机访问
不同的流类型一般支持对相关流中数据的随机访问。可以重新定位流,以便环绕跳过,首先读最后一行,再读第一行,以此类推。标准库提供一对函数来定位(seek)给定位置并告诉(tell)相关流中的当前位置。
9.1 seek和tell函数
seekg:重新定位输入流中的标记
tellg:返回输入流中标记的当前位置
seekp:重新定位输出流中的标记
tellp:返回输出流中标记的当前位置
逻辑上,只能在istream或者ifstream或者istringstream上使用g版本,并且只能在ostream类型或其派生类性ofstream或者ostringstream之上使用p版本。iostream对象,fstream或者stringstream对象对相关流既可以读也可以写,可以使用两个版本的任意版本。9.
9.2 只有一个标记
虽然标准库区分输入和输入而有两个版本,但它只在文件中维持一个标记——没有可区分的读标记和写标记。
只是试图在ifstream对象上调用tellp的时候,编译器将会给出错误提示。反之亦然。
使用既可以读又能写的fstream类型以及stringstream类型的时候,只有一个保存数据的缓冲区和一个表示缓冲器中当前位置的标记,标准库将g版本和p版本都映射到这个标记。
9.3 普通iostream对象一般不允许随机访问。
9.4 重新定位标记
seekg(new_position); seekp (new_position); seekg( offset, dir); seekp( offset, dir);
第一个版本将当前位置切换到给定地点,第二个版本接受一个偏移量以及从何处计算偏移的指示器。
9.5 访问标记
tell函数返回的一个值,使用适当类的pos_type成员来保存。
10,一个实例
假定给定一个文件来读,我们将在文件的末尾写一个新行,改行包含了每一行开头的相对位置(程序不必写第一行的偏移量,因为它总是0)。例如给定下面的文件,
abcd
efg
hi
j
这段程序应产生修改过的文件如下:
abcd
efg
hi
j
5 9 12 14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
#include <iostream> #include <fstream> #include <string> using std::fstream; using std::cerr; using std::endl; using std::ifstream; using std::ofstream; using std::string; using std::getline; using std::cout; //使用命名空间std; int main() { fstream inOut( "copyOut.txt" , fstream::ate | fstream::in | fstream::out); //用ate方式打开,会将文件的位置定位到文件末尾。 if ( !inOut ) { cerr << "unable to open file" <<endl; return EXIT_FAILURE; } inOut.seekg(-1,fstream::end); //去最后一个字符 if ( inOut.peek() != 10) //如果文件的最后一个字符不是换行符,请添加它。 { inOut.seekg(0,fstream::end); inOut.put( '\n' ); } inOut.seekg(0,fstream::end); ifstream::pos_type endMark = inOut.tellg(); //记录最后的位置。 inOut.seekg(0,fstream::beg); int cnt = 0; //累加器用于字节计数 string line; //保持每行输入 while ( inOut && inOut.tellg() != endMark && getline(inOut , line) ) { cnt += line.size() + 1; // 添加1以计算新行 ifstream::pos_type mark = inOut.tellg(); inOut.seekp( 0, fstream::end); //设置写标记结束 inOut << cnt; if ( mark != endMark) inOut << " " ; inOut.seekg(mark); //恢复读取位置 } inOut.clear(); //清除标志,以防我们遇到错误 inOut.seekp(0 , fstream::end); //寻求结束 inOut << endl; //在文件末尾写一个换行符 return 0; } 除特别注明外,本站所有文章均为 赢咖4注册 原创,转载请注明出处来自C++的那些事:流与IO类 |