📄 14章 文件处理.txt
字号:
14.8 建立随机访问文件
ostream成员函数write把从内存中指定位置开始的固定个数的字节送到指定流中,当流与文件关联时,数据写人到“put'’文件位置指针所指示的位置。istream成员函数read把固定个数的字节从指定流输入到内存中指定地址开始的区域。如果流与文件相关联,则该字节从"get"文件位置指针指定的文件地址开始输入。
现在,将整型number写入文件时,不是用下列语句:
outFile << number;
对4字节整数打印1位或ll位(10位加一个符号位,各要1字节存储空问),而改用:
outFile.write( reinterpret_cast<const char *>( &number ),
sizeof( number ));
这种方法总是写入4字节(在4字节整数机器上)。write函数要求一个const char *类型的参数为第一个参数,因此我们用reinterpret_cast<const char*>强制类型转换运算符将number的地址变为const char *指针。write的第二个参数是size_t类型的整数,指定写入的字节数。可以看出,istresm函数read可以将4个字节读回到整型变量number中。
随机存取文件处理程序很少只把一个域写入文件中,通常会一次写入一个结构或一个类对象。
下面举一个例子。
考虑如下的问题描述:
建立一个能够存储100个定长记录的借贷处理系统。每一条记录由账号(用作记录关键字)、姓、名和借贷金额组成。程序要能够更新、插入和删除一条记录以及能够以格式化文本形式列出所有的记录。要求使用随机访问文件。
以下几节介绍了建立借贷处理程序所需的技术。图14.11中的程序说明了怎样打开一个随机访问文件、怎样用struct定义—条记录格式(在cIntdata.h头文件中定义)以及怎样把数据写入磁盘。
程序用write函数和空结构初始化了文件"credit.dat"的所有100条记录。每一个空结构中,账号都为0,姓氏和名为NULL,借贷金额为0.0。文件以这种方式初始化后就在磁盘上建立了存储文件的空间,并且能够确定某条记录是否包含数据。
在图14.11中,下列语句(第34行到第36行):
outCredit.write(
reinterpret cast<const char*>(&blankClient),
将长度为sizeof(clientData)的blankClient结构写入与ofstream的对象outCredit相关联的文件credit.dat。记住,运算符sizeof返回括号中对象的长度(字节数,见第5章)。注意,第34行函数write的第一个参数应为const char*类型,但&blankClient的数据类型为clientData *。要将&blankClient变为相应指针类型,下列表达式:
reinterpret cast<const char *>( &blankClient )
用强制类型转换运算符reinterpret_cast将blankClient地址变为const char *类型,因此调用write能顺利编译,而不产生语法错误。
1 // Fig. 14.11: clntdata.h
2 // Definition of struct clientData used in
3 // Figs. 14.11, 14.12, 14.14 and 14.15.
4 #ifndef CLNTDATA_H
5 #define CLNTDATA_H
6
7 struct clientData {
8 int accountNumber;
9 char lastName[15];
10 char firstName[10];
11 float balance;
12 } ;
13
14 #endif
15 // Fig. 14.11: fig14_11.cpp
16 // Creating a randomly accessed file sequentially
17 #include <iostream.h>
18 #include <fstream.h>
19 #include <stdlib.h>
20 #include "clntdata.h"
21
22 int main()
23 {
24 ofstream outCredit( "credit.dat", ios::out );
25
26 if ( !outCredit ) {
27 cerr << "File could not be opened." << endl;
28 exit( 1 );
29 }
3O
31 clientData blankClient = { 0, "", "", 0.0 };
32
33 for ( int i = 0; i < 100; i++ )
34 outCredit.write(
35 reinterpret_cast<const char *>( &blankClient ),
36 sizeof( clientData ) );
37 return 0;
38 }
图14. 11 顺序生成随机访问文件
14.9 向随机访问文件中随机地写入数据
图14.12 中的程序把数据写到文件“credit dm”中。ostream的函数seekp和write用来将数据存储在文件中指定的位置。程序先用函数seekp把“put”文件位置指针指向文件中指定的位置,然后用write函数写入数据。执行范例见图14. 13。注意图14. 12的程序包括图14.11中定义的头文件clntdata h。
1 // Fig. 14.12: figl4_12.cpp
2 // Writing to a random access file
3 #include <iostream.h>
4 #include <fstream.h>
5 #include <stdlib.h>
6 #include "clntdata.h"
7
8 int main()
9 {
10 ofstream outCredit( "credit.dat", ios::ate );
11
12 if ( !outCredit ) {
13 cerr << "File could not be opened." << endl;
14 exit( 1);
15 }
16
17 cout << "Enter account number "
18 << "(1 to 100, 0 to end input)\n? ";
19
20 clientData client;
21 cin >> client.accountNumber;
22
23 while ( client.accountNumber > 0 &&
24 client.accountNumber <= 100 ) {
25 cout << "Enter lastname, firstname, balance\n? ";
26 cin >> client.lastName>> client.firstName
27 >> client.balance;
28
29 outCredit.seekp( ( client.accountNumber - 1 ) *
30 sizeof( clientData ) );
31 outCredit.write(
32 reinterpret_cast<const char *>( &client ),
33 sizeof( clientData ) );
34
35 cout << "Enter account number\n? ";
36 cin >> client.accountNumber;
37 }
38
39 return 0;
4O }
图14. 12 把数据随机地写人随机访问文件中
Enter account number (1 to 100, 0 to end input)
? 37
Enter lastname,firstname,balance
? Barker Doug 0.00
Enter account number
? 29
Enter lastname, firstname, balance
? Barker Nancy -24.54
Enter account number
? 96
Enter lastname, firstname, balance
? Stone Sam 34.98
Enter account number
? 88
Enter lastname, firstname, balance
? Smith Dave 258.34
Enter account number
? 33
Enter lastname, firstname, balance
? Dunn Stacey 314.33
Enter account number
?0
图14.13 图14.12中程序的示例输出
第29行和第30行:
outCredit.seekp( ( client.accountNumber - 1 ) *
sizeof( ciientData ) );
将outCredit对象的“put”文件位置指针放在(client.accountNumber-1)*sizof(clientData)求出的字节位置处。由于账号在1到100之间.因此计算记录的字节位置时要从账号减1。这样,对于记录1,文件位置指针设置为文件的字节0。注意ofstream的对象outCredit用文件打开方式ios::ate打开。“put”文件位置指针最初设置为文件末尾,但数据可以在文件中的任何地方写入。
14.10 从随机访问文件中顺序地读取数据
上面几节生成了随机访问文件并将数据写入这个文件中。本节要开发一个程序,顺序读取这个文件.只打印包含数据的记录。该程序还有另一好处,将在本节最后说明,读者不妨先猜猜看。
istream的函数read从指定流的当前位置向对象输入指定字节数。例如,图14.14中下列语句:
inCredit.read(reinterpret_cast<char *)(&client),
sizeof(clientData));
从与ifstrem的对象inCredit相关联的文件中读取sizeof(clientData)指定的字节数,并将数据存放在结构client中。注意函数read要求第一个参数类型为char*。由于&client的类型为clientData *,因此&client要用强制类型转换运算符interpret_cast变为char*。注意图14.14中的程序中包括图14.11定义的头文件clntdata. h。
1 // Fig. 14.14: figl4_14.cpp
2 // Reading a random access file sequentially
3 #include <iostream.h>
4 #include <iomanip.h>
5 #include <fstream.h>
6 #include <stdlib.h>
7 #include "clntdata.h"
8
9 void outputLine( ostream&, const clientData & );
10
11 int main()
12 {
13 ifstream inCredit( "credit.dat", ios::in );
14
15 if ( !inCredit ) {
16 cerr << "File could not be opened." << endl;
17 exit( 1 );
18 }
19
20 cout << setiosflags( ios::left ) << setw( 10 ) << "Account"
21 << setw( 16 ) << "Last Name" << setw( 11 )
22 << "first Name" << resetiosflags( ios::left )
23 << setw( 10 ) << "Balance" << endl;
24
25 clientData client;
26
27 inCredit.read( reinterpret_cast<char *> ( &client ),
28 sizeof( clientData ) );
29
30 while ( inCredit && !inCredit.eof() ) {
31
32 if { client.accountNumber != 0 )
33 outputLine( cout, client );
34
35 inCredit.read( reinterpret_cast<char *>( &client ),
sizeof( clientData ) );
36
37 }
38
39 return 0;
40 }
41
42 void outputLine( ostream &output, const clientData &c )
43 {
44 output << setiosflags( ios::left ) << setw( 10 )
45 << c.accountNumber << setw( 16 ) << c.lastName
46 << setw( 11 ) << c.firstName << setw( 10 )
47 << setprecision( 2 ) << resetiosflags( ios::left )
48 << setiosflags( ios::fixed | ios::showpoint )
49 << c.balance << '\n';
5O }
输出结果:
Account Last Name First Name Balance
29 Brown Nancy -24.54
33 Dunn Stacey 319.33
37 Barker Doug 9.00
88 Smith Dave 258.34
96 Stone Sam 34.98
图14.14 从随机访问文件中顺序地读取数据
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -