⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 14章 文件处理.txt

📁 C++大学教程txt版中文版 C++大学教程txt版中文版
💻 TXT
📖 第 1 页 / 共 5 页
字号:
9
10 int main()
11 {                     
12   // ifstream constructor opens the file
13   ifstream inClientFile( "clients.dat", ios::in );
14
15   if { !inClientFile ) {
16     cerr << "File could not be opened\n";
17     exit( 1 );
18     }
19
20   int account;
21   char name[ 30 ] ;
22   double balance;
23
24   cout << setiosflags( ios::left ) << setw( 10 ) << "Account"
25       << setw( 13 ) << "Name" << "Balance\n";
26
27   while ( inCiientFile >> account >> name >> balance )
28     outputLine( account, name, balance );
29
30   return 0;  // ifstream destructor closes the file
31 }
32
33 void outputLine( int acct, const char *name, double bal )
34 {
35   cout << setiosflags( ios::left ) << setw( 10 ) << acct
36       << setw( 13 ) << name << setw( 7 ) << setprecision( 2 )
37       << resetiosflags( ios::left )
38       << setiosflags( ios::fixed | ios::showpoint )
39       << bal << '\n';
40 }

输出结果:
Account     Name       Balance
i00        Jones        24.98
200        Doe         345.67
300        White         0.00
400        Stone       -42.16
500        Rich        224.62

                          图14.7 读取并打印一个顺序文件

    为了按顺序检索文件中的数据,程序通常要从文件的起始位置开始读取数据,然后连续地读取所有的数据,直到找到所需要的数据为止。程序执行中可能需要按顺序从文件开始位置处理文件中的数据好几次。istreatrl类和ostream类都提供成员函数,使程序把“文件位置指针”(file position pointer,指示读写操作所在的下一个字节号)重新定位。这些成员函数是istream类的seekg(“seekget”)和ostream类的seekp(“seek put”)。每个istream对象有个get指针,表示文件中下一个输入
    相距的字节数,每个ostream对象有一个put指针,表示文件中下一个输出相距的字节数。下列语句:
    inclientFile.seekg( 0 );
    将文件位置指针移到文件开头(位置0),连接inclientFile。seekg的参数通常为long类型的整数。
第二个参数可以指定寻找方向,ios::beg(默认)相对于流的开头定位,ios::cur相对于流当前位置定位,ios::end相对于流结尾定位。文件位置指针是个整数值,指定文件中离文件开头的相对位置(也称为离文件开头的偏移量)。下面是一些get文件位置指针的例子:

    // position to the nth byte of fileObject
    // assumes ios::beg
    fileObject.seekg( n );
    // position n bytes forward in fileObject
    fileObject.seekg( n, ios::cur );
    // position y bytes back from end of fileObject
    fileObject.seekg( y, ios::end );
    // position at end of fileObject
    fileObject.seekg( o, ios::end );
    ostream成员函数seekp也可以进行类似的操作。成员函数tellg和tellp分别返回get和put指针的当前位置。下列语句将get文件位置指针值赋给long类型的变量location。
    location = filObject.tellg();
    图14. 8中的程序可用来显示无借贷客户、公司债主和欠款客户的清单。公司欠债主的金额用负数表示,欠公司的金额用正数表示。程序显示了一个菜单.管理人员键入前三个选项中的一个可获取某方面的借贷信息。选项1显示出无借贷客户的清单,选项2显示公司债主的清单,选项3显示欠款客户的清单,选项4终止程序的运行。输入无效值时只是再次提示更新选择。图14. 9是程序的简单输出。

1 // Fig. 14.8; fig14_08.cpp
2 // Credit inquiry program
3 #include <iostream.b>
4 #include <fstream.h>
5 #include <iomanip.h>
6 #include <stdlib.h>
7
8 enum RequestType { ZERO_BALANCE = 1, CREDIT_BALANCE,
9                DEBIT_BALANCE, END } ;
10 int getRequest();
11 bool shouldDisplay( int, double );
12 void outputLine( int, const char *, double );
13
14 int main()
15 {
16   // ifstrem constructor opens the file
17   ifstream inClientFile( "clients.dat", ios::in );
18
19   if( !inClientFile) {
20     cerr << "File could not be opened" << endl;
21     exit( 1) ;
22   }
23
24   int request;
25   int account;
26   char name[ 30 ] ;
27   double balance;
28
29   cout << "Enter request\n"
30        << " 1 - List accounts with zero balances\n"
31        <<  " 2 - List accounts with credit balances\n"
32        << " 3 - List accounts with debit balances\n"
33        << " 4 - End of run";
34   request = getRquest();
35
36   while ( request != END ) {
37
38     switch ( request ) {
39        case ZERO_BALANCE:
40            cout << "\nAccounts with zero balances:\n";
41           break;
42        case CREDIT_BALANCE:
43            cout << "\nAccounts with credit balances:\n";
44          break;
45        case DEBIT_BALANCE:
46            cout <<"\nAccounts with debit balances:\n";
47            break;
48     }
49
50     inClientFile >> account >> name >> balance;
51
52         while (  !inClientFile.eof()  ) {
53            if  ( shouldDisplay( request, balance ) )
54                outputLine( account, name, balance );
55       
56                inClientFile >> account >> name >> balance;
57     }
58
59     inClientFile.clear();   // reset eof for next input
60     inClientFile.seekg( 0 ); // move to beginning of file
61     request = getRequest();
62     }
63
64   cout << "End of run." << endl;
65
66   return 0;  // ifstream destructor closes the file
67 }
68
69 int getRequest()
7O {
71   int request;
73   do {
74       cout << "\n? ";
75       cin >> request;
76   } while( request < ZERO BALANCE && request > END );
77
78   return request;
79   }  
8O
81 bool shouldDisplay( int type, double balance )
82 {
83   if ( type == CREDIT_BALANCE && balance < 0 )
84      return true;
86   if ( type == DEBIT_BALANCE && balance > 0 )
87     return true;
89   if ( type == ZERO BALANCE && balance == 0 )
90     return true; 
92   return false;
93 }
95 void outputLine( int acct, const char *name, double bal )
96 {
97   cout << setiosflags( ios::left ) << setw( 10 ) << acct
98        << setw( 13 ) << name << setw( 7 ) << setprecision( 2 )
99        << resetiosflags( ios::left                    
100       << setiosflags( ios::fixed | ios::showpoint )
101       << bal << '\n';
102 }

                                  图14. 8 借贷查询程序

Enter request
1 - List accounts with zero balances
2 - List accounts with credit balances
3 - List accounts with debit balances
4  End of run.
?  1

Accounts with zero balances:
300         white           0.00

?  2

Accounts with credit balances:
400       stone        -42.16

?  3

Accounts with debit banlances:
100          jones        24.98
200          Doe         345.67
500          Rich        224.62
?  4

End of run

                              图 149  图14. 8中程序的示例输出
 
C++大学教程 第14章 文件处理  
 
14.6 更新顺序访问文件
    14. 4 节介绍了格式化和写入顺序访问文件的数据修改时会有破坏文件中其他数据的危险。例如,如果要把名字"White"改为"Worthinglon",则不是简单地重定义旧的名字。White的记录是以如下形式写人文件中的:
    300 White 0.00
    如果用新的名字从文件中相同的起始位置重写该记录,记录的格式就成为:
    300 Worthington 0.00
因为新的记录长度大于原始记录的长度,所以从“Worthington"的第二个“0”之后的字符将重定义文件中的下一条顺序记录。出现该问题的原因在于:在使用流插入运算符<<和流读取运算符>>的格式化输人,输出模型中,域的大小是不定的,因而记录的大小也是不定的。例如,7、14、-117、2047和27383都是int类型的值,虽然它们的内部存储占用相同的字节数,但是将它们以格式化文本打印到屏幕上或存储在磁盘上时要占用不同大小的域。因此,格式化输入,输出模型通常不用来更新已有的记录。
    也可以修改上述名字,但比较危险。比如,在300 Whlte 0.00之前的记录要复制到一个新的文件中,然后写入新的记录并把300 White 0.00之后的记录复制到新文件中。这种方法要求在更新一条记录时处理文件中的每一条记录。如果文件中一次要更新许多记录,则可以用这种方法。

14.7 随机访问文件
    前面介绍了生成顺序访问文件和从顺序访问文件搜索特定信息。顺序访问文件不适合快速访问应用程序,即要立即找到特定记录的信息。快速访问应用程序的例子有航空订票系统、银行系统、销售网点系统、自动柜员机和其他要求快速处理特定数据的事务处理系统(transaction processing system)。银行要面对成千上万的客户,但自动柜员机能在瞬间作出响应。这种快速访问应用程序是用随机访问文件(random access file)实现的。随机访问文件的各个记录可以直接快速访问,而不需要进行搜索。
    前面曾介绍过.C++不提供文件结构。因此应用程序要自己生成随机访问文件。虽然实现随机访问文件还有其他方法,但是本书的讨论只限于使用定长记录的这种简洁明了的方法。因为随机访问文件中的每一条记录都有相同的长度,所以能够用记录关键字的函数计算出每一条记录相对于文件起始点的位置。不久就会学到怎样立即访问到文件甚至大型文件中指定的记录。
    图14.10 反映了由定长记录组成的随机访问文件的一种观点(每一条记录为100字节)。它就像一列火车,一些车箱是空的,还有一些车箱满载货物,但是火车中的每节车箱具有相同的长度。
    可以在不破坏其他数据的情况下把数据插入到随机访问文件中。也能在不重写整个文件的情况下更新和删除以前存储的数据。下面几节要讨论怎样建立随机访问文件、键入数据、顺序和随机地读取数据、更新数据和删除不再需要的数据。


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -