chapter 17 file processing chapter 17 file processing

62
Chapter 17 Chapter 17 File Processing File Processing

Upload: louisa-briggs

Post on 17-Jan-2016

272 views

Category:

Documents


13 download

TRANSCRIPT

Page 1: Chapter 17 File Processing Chapter 17 File Processing

Chapter 17 Chapter 17 File Processing File Processing

Page 2: Chapter 17 File Processing Chapter 17 File Processing

17.1 Introduction17.1 IntroductionFiles are used for data

persistence◦Secondary storage devices are used

to store files: Magnetic disks Optical disks Tapes

Page 3: Chapter 17 File Processing Chapter 17 File Processing

17.2 The Data Hierarchy17.2 The Data HierarchyBits (“binary digits”)

◦Can assume one of two values, 0 or 1◦Smallest data item that computers

support.Characters

◦Composed of bits (1s and 0s)◦A character set is the set of all

characters used on a particular computer.

◦chars are stored in bytes (8 bits) wchar_ts are stored in more than one byte

Page 4: Chapter 17 File Processing Chapter 17 File Processing

17.2 The Data Hierarchy17.2 The Data HierarchyFields

◦A Field is composed of characters.◦Each conveys some meaning.

Records◦A record is composed of several fields.◦It can be represented as a class in C++

Example An employee’s record might include id, name,

address, etc.

◦A record key is a field unique to each record.

Page 5: Chapter 17 File Processing Chapter 17 File Processing

Fig. 17.1Fig. 17.1 | Data hierarchy.| Data hierarchy.

Page 6: Chapter 17 File Processing Chapter 17 File Processing

17.2 The Data Hierarchy17.2 The Data HierarchyFile

◦A file is composed of a group of related records. Example

A payroll file containing one record for each employee

◦Many ways to organize records in a file For example, in a sequential file

Records are stored in order by a record-key field

Database◦A database is composed of a group of related

files, which is managed by a group of programs called a database management system (DBMS).

Page 7: Chapter 17 File Processing Chapter 17 File Processing

17.3 Files and Streams17.3 Files and StreamsFiles

◦A file is viewed by C++ as a sequence of bytes and ends either with an end-of-file marker or at a system-recorded byte number. A file is performed through stream objects <fstream> header file

Stream class templates basic_ifstream – for file input basic_ofstream – for file output basic_fstream – for file input and output

Files are opened by creating objects of stream template specializations

Page 8: Chapter 17 File Processing Chapter 17 File Processing

Fig. 17.2Fig. 17.2 | C++’s view of a file of | C++’s view of a file of nn bytes. bytes.

檔案的內容為一串位元組組成,結尾有一個檔尾標記( end-of-file marker )用來標示檔案結尾;在文字檔中的換行的位置由換行字元(’ /n’ )所標示。

Page 9: Chapter 17 File Processing Chapter 17 File Processing

Fig. 17.3Fig. 17.3 | Portion of stream I/O template | Portion of stream I/O template hierarchy.hierarchy.

Page 10: Chapter 17 File Processing Chapter 17 File Processing

檔案讀寫的基本流程檔案讀寫的基本流程

開檔開檔

檔案操作檔案操作

關檔關檔

Page 11: Chapter 17 File Processing Chapter 17 File Processing

17.4 Creating a Sequential File17.4 Creating a Sequential File

Creating an ofstream object◦File open for output◦Constructor takes two arguments

A filename If the file doe not exist, it is first created

A file-open mode ios::out – the default mode

The preexisting data in the file is overwritten. ios::app

New data is appended to the end of the file

◦This member function open on existing object can be also used.

Page 12: Chapter 17 File Processing Chapter 17 File Processing

17.4 Creating a Sequential File17.4 Creating a Sequential File

◦Use an ofstream object and the stream insertion operator to write a file

◦Member function close() to release the file resource Implicitly performed by ofstream’s destructor

ios operators (usable with ofstream)◦Operator member function operator!

Returns true if either the failbit or badbit is set

◦Operator member function operator void * Converts the stream to a pointer

The null pointer if either the failbit or badbit is set

Page 13: Chapter 17 File Processing Chapter 17 File Processing

File Open for OutputFile Open for OutputExample 1

Example 2

#include <fstream> void main() { ofstream output(“test.txt”, ios::out); … }

#include <fstream> void main() { ofstream output; output.open(“test.txt”, ios::app); … }

檔名

寫檔模式

Page 14: Chapter 17 File Processing Chapter 17 File Processing

1 // Fig. 17.4: Fig17_04.cpp

2 // Create a sequential file.

3 #include <iostream>

4 using std::cerr;

5 using std::cin;

6 using std::cout;

7 using std::endl;

8 using std::ios;

9

10 #include <fstream> // file stream

11 using std::ofstream; // output file stream

12

13 #include <cstdlib>

14 using std::exit; // exit function prototype

15

16 int main()

17 {

18 // ofstream constructor opens file

19 ofstream outClientFile( "clients.dat", ios::out );

20

21 // exit program if unable to create file

22 if ( !outClientFile ) // overloaded ! operator

23 {

24 cerr << "File could not be opened" << endl;

25 exit( 1 );

26 } // end if

27

28 cout << "Enter the account, name, and balance." << endl

29 << "Enter end-of-file to end input.\n? ";

Fig17_04.cpp (1 of 2)

Open file client.dat for output

Overloaded operator! will return true if the file did not open successfully

Page 15: Chapter 17 File Processing Chapter 17 File Processing

30

31 int account;

32 char name[ 30 ];

33 double balance;

34

35 // read account, name and balance from cin, then place in file

36 while ( cin >> account >> name >> balance )

37 {

38 outClientFile << account << ' ' << name << ' ' << balance << endl;

39 cout << "? ";

40 } // end while

41

42 return 0; // ofstream destructor closes file

43 } // end main Enter the account, name, and balance. Enter end-of-file to end input. ? 100 Jones 24.98 ? 200 Doe 345.67 ? 300 White 0.00 ? 400 Stone -42.16 ? 500 Rich 224.62 ? ^Z

Fig17_04.cpp (2 of 2)

Overloaded operator void * will return the null pointer 0 (false) when the user enters the end-of-file indicator

Write data to client.dat using the stream insertion operator

正常來說,你需要特別指定關檔的動作,但在這裡, ofstream 物件的解構子自動就會關閉檔案;你也可以呼叫該物件的 close() 函式明確指定關檔動作。例如: outClientFile.close();

Page 16: Chapter 17 File Processing Chapter 17 File Processing

Fig. 17.6Fig. 17.6 | End-of-file key combinations for various popular computer | End-of-file key combinations for various popular computer systems. systems.

Computer system Keyboard combination

UNIX/Linux/Mac OS X <ctrl-d> (on a line by itself)

Microsoft Windows <ctrl-z> (sometimes followed by pressing Enter)

VAX (VMS) <ctrl-z>

Page 17: Chapter 17 File Processing Chapter 17 File Processing

Common Programming Error Common Programming Error 17.117.1

Use caution when opening an existing file for output (ios::out), especially when you want to preserve the file’s contents, which will be discarded without warning.

Page 18: Chapter 17 File Processing Chapter 17 File Processing

Fig. 17.5Fig. 17.5 | File open modes.| File open modes.

Mode Description

ios::app Append all output to the end of the file.

ios::ate Open a file for output and move to the end of the file (normally used to append data to a file). Data can be written anywhere in the file.

ios::in Open a file for input.

ios::out Open a file for output.

ios::trunc Discard the file’s contents if they exist (this also is the default action for ios::out).

ios::binary Open a file for binary (i.e., nontext) input or output.

Page 19: Chapter 17 File Processing Chapter 17 File Processing

Common Programming Error Common Programming Error 17.217.2Not opening a file before

attempting to reference it in a program will result in an error.

Indicate the following error:

#include <fstream> using namespace std; void main() { int x=2, y=4; ofstream output; output << x << y << endl; … }

Page 20: Chapter 17 File Processing Chapter 17 File Processing

Performance Tip 17.1Performance Tip 17.1

Closing files explicitly when the program no longer needs to reference them can reduce resource usage (especially if the program continues execution after closing the files).

Page 21: Chapter 17 File Processing Chapter 17 File Processing

第二次寫資料到檔案去時,如何知道要從什麼地方開始寫起?

30

31 int account;

32 char name[ 30 ];

33 double balance;

34

35 // read account, name and balance from cin, then place in file

36 while ( cin >> account >> name >> balance )

37 {

38 outClientFile << account << ' ' << name << ' ' << balance << endl;

39 cout << "? ";

40 } // end while

41

42 return 0; // ofstream destructor closes file

43 } // end main Enter the account, name, and balance. Enter end-of-file to end input. ? 100 Jones 24.98 ? 200 Doe 345.67 ? 300 White 0.00 ? 400 Stone -42.16 ? 500 Rich 224.62 ? ^Z

當開檔時,即會有一個指標指向檔案的內容代表目前下一次讀 / 寫的位置。以上面的程式碼為例,當執行第 38 行時,檔案指標就會剛好停在緊接著換行字元後面的位置;下一次的寫檔,就從這個位置開始寫起。

檔案指標檔案指標

Page 22: Chapter 17 File Processing Chapter 17 File Processing

17.5 Reading Data from a 17.5 Reading Data from a Sequential FileSequential File

Creating an ifstream object◦Opens a file for input◦Constructor takes two arguments

A filename A file-open mode

ios::in – the default mode Can only read from the file

◦Can also use member function open on an existing object Takes same arguments as the constructor

Page 23: Chapter 17 File Processing Chapter 17 File Processing

Good Programming Practice 17.1Good Programming Practice 17.1

Open a file for input only (using ios::in) if the file’s contents should not be modified. This prevents unintentional modification of the file’s contents and is an example of the principle of least privilege.

Page 24: Chapter 17 File Processing Chapter 17 File Processing

1 // Fig. 17.7: Fig17_07.cpp

2 // Reading and printing a sequential file.

3 #include <iostream>

4 using std::cerr;

5 using std::cout;

6 using std::endl;

7 using std::fixed;

8 using std::ios;

9 using std::left;

10 using std::right;

11 using std::showpoint;

12

13 #include <fstream> // file stream

14 using std::ifstream; // input file stream

15

16 #include <iomanip>

17 using std::setw;

18 using std::setprecision;

19

20 #include <string>

21 using std::string;

22

23 #include <cstdlib>

24 using std::exit; // exit function prototype

25

26 void outputLine( int, const string, double ); // prototype

Fig17_07.cpp (1 of 3)

Page 25: Chapter 17 File Processing Chapter 17 File Processing

27

28 int main()

29 {

30 // ifstream constructor opens the file

31 ifstream inClientFile( "clients.dat", ios::in );

32

33 // exit program if ifstream could not open file

34 if ( !inClientFile )

35 {

36 cerr << "File could not be opened" << endl;

37 exit( 1 );

38 } // end if

39

40 int account;

41 char name[ 30 ];

42 double balance;

43

44 cout << left << setw( 10 ) << "Account" << setw( 13 )

45 << "Name" << "Balance" << endl << fixed << showpoint;

46

47 // display each record in file

48 while ( inClientFile >> account >> name >> balance )

49 outputLine( account, name, balance );

50

51 return 0; // ifstream destructor closes the file

52 } // end main

Fig17_07.cpp (2 of 3)

Open clients.dat for input

Overloaded operator void * returns a null pointer 0 (false) when the end of clients.dat is reached

Overloaded operator! returns true if clients.dat was not opened successfully

ifstream destructor implicitly closes the file

Page 26: Chapter 17 File Processing Chapter 17 File Processing

53

54 // display single record from file

55 void outputLine( int account, const string name, double balance )

56 {

57 cout << left << setw( 10 ) << account << setw( 13 ) << name

58 << setw( 7 ) << setprecision( 2 ) << right << balance << endl;

59 } // end function outputLine Account Name Balance 100 Jones 24.98 200 Doe 345.67 300 White 0.00 400 Stone -42.16 500 Rich 224.62

Fig17_07.cpp (3 of 3)

Page 27: Chapter 17 File Processing Chapter 17 File Processing

17.5 Reading Data from a 17.5 Reading Data from a Sequential FileSequential FileFile-position pointer

◦ The byte number of the next byte to be read or written

◦ Member functions seekg and seekp (of istream and ostream, respectively) The file-position pointer repositioned to the specified

location Desired offset is taken.

A second argument can specify the seek direction ios::beg – the default

Positioning relative to the beginning ios::cur

Positioning relative to the current position ios::end

Positioning relative to the end

Page 28: Chapter 17 File Processing Chapter 17 File Processing

17.5 Reading Data from a 17.5 Reading Data from a Sequential FileSequential File◦Examples

fileObject.seekg( n ); Position to the nth byte of fileObject

fileObject.seekg( n, ios::cur ); Position n bytes forward in fileobject

fileObject.seekg( n, ios::end ); Position n bytes back from end of fileObject

fileObject.seekg( 0, ios::end ); Position at end of fileObject

Page 29: Chapter 17 File Processing Chapter 17 File Processing

17.5 Reading Data from a 17.5 Reading Data from a Sequential FileSequential File

File-position pointer◦Member functions tellg and tellp (of istream and ostream, respectively) Returns current position of the file-position

pointer as type long Example

Location = fileObject.tellg();

Page 30: Chapter 17 File Processing Chapter 17 File Processing

程式範例說明程式範例說明建立一個信用處理程式。

◦ 檔案 clients.dat 用來記錄所有客戶的資料 每一筆記錄皆包括帳戶編號、名稱、姓氏和帳戶餘額,中

間以 Tab 字元隔開 帳戶餘額( balance )小於零代表借出( credit ) 帳戶餘額大於零代表借入( debit )

◦ 程式根據使用者的輸入指示( getRequest ),列出檔案中所有 credit 或所有 debit 的資料 一筆一筆讀入程式作判斷(檔案搜尋)

Page 31: Chapter 17 File Processing Chapter 17 File Processing

1 // Fig. 17.8: Fig17_08.cpp

2 // Credit inquiry program.

3 #include <iostream>

4 using std::cerr;

5 using std::cin;

6 using std::cout;

7 using std::endl;

8 using std::fixed;

9 using std::ios;

10 using std::left;

11 using std::right;

12 using std::showpoint;

13

14 #include <fstream>

15 using std::ifstream;

16

17 #include <iomanip>

18 using std::setw;

19 using std::setprecision;

20

21 #include <string>

22 using std::string;

23

24 #include <cstdlib>

25 using std::exit; // exit function prototype

26

27 enum RequestType { ZERO_BALANCE = 1, CREDIT_BALANCE, DEBIT_BALANCE, END };

28 int getRequest();

29 bool shouldDisplay( int, double );

30 void outputLine( int, const string, double );

Fig17_08.cpp (1 of 6)

Page 32: Chapter 17 File Processing Chapter 17 File Processing

31

32 int main()

33 {

34 // ifstream constructor opens the file

35 ifstream inClientFile( "clients.dat", ios::in );

36

37 // exit program if ifstream could not open file

38 if ( !inClientFile )

39 {

40 cerr << "File could not be opened" << endl;

41 exit( 1 );

42 } // end if

43

44 int request;

45 int account;

46 char name[ 30 ];

47 double balance;

48

49 // get user's request (e.g., zero, credit or debit balance)

50 request = getRequest();

51

Fig17_08.cpp (2 of 6)

Page 33: Chapter 17 File Processing Chapter 17 File Processing

52 // process user's request

53 while ( request != END )

54 {

55 switch ( request )

56 {

57 case ZERO_BALANCE:

58 cout << "\nAccounts with zero balances:\n";

59 break;

60 case CREDIT_BALANCE:

61 cout << "\nAccounts with credit balances:\n";

62 break;

63 case DEBIT_BALANCE:

64 cout << "\nAccounts with debit balances:\n";

65 break;

66 } // end switch

67

68 // read account, name and balance from file

69 inClientFile >> account >> name >> balance;

70

71 // display file contents (until eof)

72 while ( !inClientFile.eof() )

73 {

74 // display record

75 if ( shouldDisplay( request, balance ) )

76 outputLine( account, name, balance );

77

78 // read account, name and balance from file

79 inClientFile >> account >> name >> balance;

80 } // end inner while

81

Fig17_08.cpp (3 of 6)

注意此處程式的寫法!!在 while 之前先讀入一次(而非在 while 裡面才作),主要的用意在於先讀一次才能先行判斷檔案是否為空的 / 已到結尾。

Page 34: Chapter 17 File Processing Chapter 17 File Processing

82 inClientFile.clear(); // reset eof for next input

83 inClientFile.seekg( 0 ); // reposition to beginning of file

84 request = getRequest(); // get additional request from user

85 } // end outer while

86

87 cout << "End of run." << endl;

88 return 0; // ifstream destructor closes the file

89 } // end main

90

91 // obtain request from user

92 int getRequest()

93 {

94 int request; // request from user

95

96 // display request options

97 cout << "\nEnter request" << endl

98 << " 1 - List accounts with zero balances" << endl

99 << " 2 - List accounts with credit balances" << endl

100 << " 3 - List accounts with debit balances" << endl

101 << " 4 - End of run" << fixed << showpoint;

102

103 do // input user request

104 {

105 cout << "\n? ";

106 cin >> request;

107 } while ( request < ZERO_BALANCE && request > END );

108

109 return request;

110 } // end function getRequest

111

Fig17_08.cpp (4 of 6)

Use ostream member function seekg to reposition the file-position pointer to the beginning

Page 35: Chapter 17 File Processing Chapter 17 File Processing

112 // determine whether to display given record

113 bool shouldDisplay( int type, double balance )

114 {

115 // determine whether to display zero balances

116 if ( type == ZERO_BALANCE && balance == 0 )

117 return true;

118

119 // determine whether to display credit balances

120 if ( type == CREDIT_BALANCE && balance < 0 )

121 return true;

122

123 // determine whether to display debit balances

124 if ( type == DEBIT_BALANCE && balance > 0 )

125 return true;

126

127 return false;

128 } // end function shouldDisplay

129

130 // display single record from file

131 void outputLine( int account, const string name, double balance )

132 {

133 cout << left << setw( 10 ) << account << setw( 13 ) << name

134 << setw( 7 ) << setprecision( 2 ) << right << balance << endl;

135 } // end function outputLine

Fig17_08.cpp (5 of 6)

Page 36: Chapter 17 File Processing Chapter 17 File Processing

Fig17_08.cpp (6 of 6)

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

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

? 2

Accounts with credit balances: 400 Stone -42.16

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

? 3

Accounts with debit balances: 100 Jones 24.98 200 Doe 345.67 500 Rich 224.62

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

? 4 End of run.

Page 37: Chapter 17 File Processing Chapter 17 File Processing

17.6 Updating Sequential 17.6 Updating Sequential FilesFilesUpdating a record in a sequential

file It could overwrite the next sequential record.

You would have to rewrite every record into another file This might be acceptable if you are updating many

records

1 0 0 /t J O E 3/t 2 . 5 /n 3 0 0 /t

100 JOE 32.5 300 …

Page 38: Chapter 17 File Processing Chapter 17 File Processing

17.7 Random-Access Files17.7 Random-Access FilesRandom-access files

◦Necessary for instant-access applications Such as transaction-processing systems

◦A record can be inserted, deleted or modified without affecting other records

◦Various techniques can be used Require that all records be of the same

length, arranged in the order of the record keys Program can calculate the exact location of any

record base on the record size and record key.

Page 39: Chapter 17 File Processing Chapter 17 File Processing

Fig. 17.9Fig. 17.9 | C++ view of a random-access file.| C++ view of a random-access file.

Page 40: Chapter 17 File Processing Chapter 17 File Processing

17.8 Creating a Random-17.8 Creating a Random-Access FileAccess Fileostream member function write

◦ 寫的時候要注意,每一次呼叫檔案的讀或寫,都是發生在檔案指標目前所指向的位置。

◦ First argument A const char * pointing to bytes in memory

◦ Second argument A size_t specifying the number of bytes to write

◦ Example

outFile.write( reinterpret_cast< const char * >( &number ), sizeof( number ) );

Page 41: Chapter 17 File Processing Chapter 17 File Processing

17.8 Creating a Random-Access 17.8 Creating a Random-Access FileFileOperator reinterpret_cast

◦Casting a pointer of one type to an unrelated type.

◦This is operator is performed at compile time.

◦It does not change the value of the object pointed to.

為什麼要把原本的資料 / 物件強制轉換成 char ?因為在C++ 中,一個 char 的長度就是一個 byte 。將原本的資料改用一個 char* 的指標變數來參考,將原本的資料當成一堆位元組來看待。

Page 42: Chapter 17 File Processing Chapter 17 File Processing

Error-Prevention Tip 17.1Error-Prevention Tip 17.1

It is easy to use reinterpret_cast to perform dangerous manipulations that could lead to serious execution-time errors.

Page 43: Chapter 17 File Processing Chapter 17 File Processing

Portability Tip 17.1Portability Tip 17.1

Using reinterpret_cast is compiler-dependent and can cause programs to behave differently on different platforms. The reinterpret_cast operator should not be used unless absolute necessary.

Page 44: Chapter 17 File Processing Chapter 17 File Processing

程式範例說明程式範例說明建立一個信用處理程式。

◦ 設計一個類別 ClientData 用來記錄單一位客戶的基本資料,並提供成員變數的 set 及 get 函式。

◦ 檔案 clients.dat 用來記錄所有客戶的資料 每一筆記錄皆包括帳戶編號、名稱、姓氏和帳戶餘額,每

一個欄位皆固定長度。 此檔案固定有 100 筆紀錄

Page 45: Chapter 17 File Processing Chapter 17 File Processing

1 // Fig. 17.10: ClientData.h

2 // Class ClientData definition used in Fig. 17.12–Fig. 17.15.

3 #ifndef CLIENTDATA_H

4 #define CLIENTDATA_H

5

6 #include <string>

7 using std::string;

8

9 class ClientData

10 {

11 public:

12 // default ClientData constructor

13 ClientData( int = 0, string = "", string = "", double = 0.0 );

14

15 // accessor functions for accountNumber

16 void setAccountNumber( int );

17 int getAccountNumber() const;

18

19 // accessor functions for lastName

20 void setLastName( string );

21 string getLastName() const;

22

23 // accessor functions for firstName

24 void setFirstName( string );

25 string getFirstName() const;

ClientData.h (1 of 2)

Page 46: Chapter 17 File Processing Chapter 17 File Processing

26

27 // accessor functions for balance

28 void setBalance( double );

29 double getBalance() const;

30 private:

31 int accountNumber;

32 char lastName[ 15 ];

33 char firstName[ 10 ];

34 double balance;

35 }; // end class ClientData

36

37 #endif

ClientData.h (2 of 2)

Store the first and last name in fixed-length char arrays – we cannot use strings because they do not have uniform length

Page 47: Chapter 17 File Processing Chapter 17 File Processing

1 // Fig. 17.11: ClientData.cpp

2 // Class ClientData stores customer's credit information.

3 #include <string>

4 using std::string;

5

6 #include "ClientData.h"

7

8 // default ClientData constructor

9 ClientData::ClientData( int accountNumberValue,

10 string lastNameValue, string firstNameValue, double balanceValue )

11 {

12 setAccountNumber( accountNumberValue );

13 setLastName( lastNameValue );

14 setFirstName( firstNameValue );

15 setBalance( balanceValue );

16 } // end ClientData constructor

17

18 // get account-number value

19 int ClientData::getAccountNumber() const

20 {

21 return accountNumber;

22 } // end function getAccountNumber

23

24 // set account-number value

25 void ClientData::setAccountNumber( int accountNumberValue )

26 {

27 accountNumber = accountNumberValue; // should validate

28 } // end function setAccountNumber

ClientData.cpp (1 of 3)

Page 48: Chapter 17 File Processing Chapter 17 File Processing

29

30 // get last-name value

31 string ClientData::getLastName() const

32 {

33 return lastName;

34 } // end function getLastName

35

36 // set last-name value

37 void ClientData::setLastName( string lastNameString )

38 {

39 // copy at most 15 characters from string to lastName

40 const char *lastNameValue = lastNameString.data();

41 int length = lastNameString.size();

42 length = ( length < 15 ? length : 14 );

43 strncpy( lastName, lastNameValue, length );

44 lastName[ length ] = '\0'; // append null character to lastName

45 } // end function setLastName

46

47 // get first-name value

48 string ClientData::getFirstName() const

49 {

50 return firstName;

51 } // end function getFirstName

ClientData.cpp (2 of 3)

string member function data returns an array containing the characters of the string (not guaranteed to be null terminated)

string member function size returns the length of lastNameString

Page 49: Chapter 17 File Processing Chapter 17 File Processing

52

53 // set first-name value

54 void ClientData::setFirstName( string firstNameString )

55 {

56 // copy at most 10 characters from string to firstName

57 const char *firstNameValue = firstNameString.data();

58 int length = firstNameString.size();

59 length = ( length < 10 ? length : 9 );

60 strncpy( firstName, firstNameValue, length );

61 firstName[ length ] = '\0'; // append null character to firstName

62 } // end function setFirstName

63

64 // get balance value

65 double ClientData::getBalance() const

66 {

67 return balance;

68 } // end function getBalance

69

70 // set balance value

71 void ClientData::setBalance( double balanceValue )

72 {

73 balance = balanceValue;

74 } // end function setBalance

ClientData.cpp (3 of 3)

Page 50: Chapter 17 File Processing Chapter 17 File Processing

1 // Fig. 17.12: Fig17_12.cpp

2 // Creating a randomly accessed file.

3 #include <iostream>

4 using std::cerr;

5 using std::endl;

6 using std::ios;

7

8 #include <fstream>

9 using std::ofstream;

10

11 #include <cstdlib>

12 using std::exit; // exit function prototype

13

14 #include "ClientData.h" // ClientData class definition

15

Fig17_12.cpp (1 of 2)

Page 51: Chapter 17 File Processing Chapter 17 File Processing

16 int main()

17 {

18 ofstream outCredit( "credit.dat", ios::binary );

19

20 // exit program if ofstream could not open file

21 if ( !outCredit )

22 {

23 cerr << "File could not be opened." << endl;

24 exit( 1 );

25 } // end if

26

27 ClientData blankClient; // constructor zeros out each data member

28

29 // output 100 blank records to file

30 for ( int i = 0; i < 100; i++ )

31 outCredit.write( reinterpret_cast< const char * >( &blankClient ),

32 sizeof( ClientData ) );

33

34 return 0;

35 } // end main

Fig17_12.cpp (2 of 2)

Open credit.dat in binary mode, which is required to write fixed-length records

Write the data in blankClient to credit.dat as bytes

Page 52: Chapter 17 File Processing Chapter 17 File Processing

17.9 Writing Data Randomly to a Random-17.9 Writing Data Randomly to a Random-Access FileAccess FileWriting data randomly

◦Opening for input and output in binary mode Use an fstream object Combine file-open modes ios::in, ios::out

and ios::binary Separate each open mode from the next with the

bitwise inclusive OR operator (|)

◦Use function seekp to set the “put” file-position pointer to the specific position Example calculation

( n – 1 ) * sizeof( ClientData ) Byte location for nth ClientData record

◦Use function write to output the data

Page 53: Chapter 17 File Processing Chapter 17 File Processing

1 // Fig. 17.13: Fig17_13.cpp

2 // Writing to a random-access file.

3 #include <iostream>

4 using std::cerr;

5 using std::cin;

6 using std::cout;

7 using std::endl;

8 using std::ios;

9

10 #include <iomanip>

11 using std::setw;

12

13 #include <fstream>

14 using std::fstream;

15

16 #include <cstdlib>

17 using std::exit; // exit function prototype

18

19 #include "ClientData.h" // ClientData class definition

20

21 int main()

22 {

23 int accountNumber;

24 char lastName[ 15 ];

25 char firstName[ 10 ];

26 double balance;

27

28 fstream outCredit( "credit.dat", ios::in | ios::out | ios::binary );

29

Fig17_13.cpp (1 of 4)

Create fstream outCredit to open credit.dat for input and output in binary mode

Page 54: Chapter 17 File Processing Chapter 17 File Processing

30 // exit program if fstream cannot open file

31 if ( !outCredit )

32 {

33 cerr << "File could not be opened." << endl;

34 exit( 1 );

35 } // end if

36

37 cout << "Enter account number (1 to 100, 0 to end input)\n? ";

38

39 // require user to specify account number

40 ClientData client;

41 cin >> accountNumber;

42

43 // user enters information, which is copied into file

44 while ( accountNumber > 0 && accountNumber <= 100 )

45 {

46 // user enters last name, first name and balance

47 cout << "Enter lastname, firstname, balance\n? ";

48 cin >> setw( 15 ) >> lastName;

49 cin >> setw( 10 ) >> firstName;

50 cin >> balance;

51

52 // set record accountNumber, lastName, firstName and balance values

53 client.setAccountNumber( accountNumber );

54 client.setLastName( lastName );

55 client.setFirstName( firstName );

56 client.setBalance( balance );

57

Fig17_13.cpp (2 of 4)

要求使用者新增記錄

Page 55: Chapter 17 File Processing Chapter 17 File Processing

58 // seek position in file of user-specified record

59 outCredit.seekp( ( client.getAccountNumber() - 1 ) *

60 sizeof( ClientData ) );

61

62 // write user-specified information in file

63 outCredit.write( reinterpret_cast< const char * >( &client ),

64 sizeof( ClientData ) );

65

66 // enable user to enter another account

67 cout << "Enter account number\n? ";

68 cin >> accountNumber;

69 } // end while

70

71 return 0;

72 } // end main

Fig17_13.cpp (3 of 4)

Position the “put” file-position pointer to the desired byte location

Write the ClientData record to the correct position in the file

Page 56: Chapter 17 File Processing Chapter 17 File Processing

Execution Result

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

? Brown 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

Page 57: Chapter 17 File Processing Chapter 17 File Processing

17.10 Reading from a Random-Access File 17.10 Reading from a Random-Access File SequentiallySequentially

Sequentially reading a random-access file◦ifstream member function read

A number of bytes are input from the current file position in the stream into an object

First argument A char * pointing to the object in memory

Second argument A size_t specifying the number of bytes to input

Page 58: Chapter 17 File Processing Chapter 17 File Processing

1 // Fig. 17.14: Fig17_14.cpp

2 // Reading a random access file sequentially.

3 #include <iostream>

4 using std::cerr;

5 using std::cout;

6 using std::endl;

7 using std::fixed;

8 using std::ios;

9 using std::left;

10 using std::right;

11 using std::showpoint;

12

13 #include <iomanip>

14 using std::setprecision;

15 using std::setw;

16

17 #include <fstream>

18 using std::ifstream;

19 using std::ostream;

20

21 #include <cstdlib>

22 using std::exit; // exit function prototype

23

24 #include "ClientData.h" // ClientData class definition

25

26 void outputLine( ostream&, const ClientData & ); // prototype

27

Fig17_14.cpp (1 of 3)

Page 59: Chapter 17 File Processing Chapter 17 File Processing

28 int main()

29 {

30 ifstream inCredit( "credit.dat", ios::in );

31

32 // exit program if ifstream cannot open file

33 if ( !inCredit )

34 {

35 cerr << "File could not be opened." << endl;

36 exit( 1 );

37 } // end if

38

39 cout << left << setw( 10 ) << "Account" << setw( 16 )

40 << "Last Name" << setw( 11 ) << "First Name" << left

41 << setw( 10 ) << right << "Balance" << endl;

42

43 ClientData client; // create record

44

45 // read first record from file

46 inCredit.read( reinterpret_cast< char * >( &client ),

47 sizeof( ClientData ) );

48

49 // read all records from file

50 while ( inCredit && !inCredit.eof() )

51 {

52 // display record

53 if ( client.getAccountNumber() != 0 )

54 outputLine( cout, client );

55

Fig17_14.cpp (2 of 3)

在 while 之前先讀入一次(而非在 while 裡面才作),主要的用意在於先讀一次才能先行判斷檔案是否為空的 / 已到結尾。

Page 60: Chapter 17 File Processing Chapter 17 File Processing

56 // read next from file

57 inCredit.read( reinterpret_cast< char * >( &client ),

58 sizeof( ClientData ) );

59 } // end while

60

61 return 0;

62 } // end main

63

64 // display single record

65 void outputLine( ostream &output, const ClientData &record )

66 {

67 output << left << setw( 10 ) << record.getAccountNumber()

68 << setw( 16 ) << record.getLastName()

69 << setw( 11 ) << record.getFirstName()

70 << setw( 10 ) << setprecision( 2 ) << right << fixed

71 << showpoint << record.getBalance() << endl;

72 } // end function outputLine Account Last Name First Name Balance

29 Brown Nancy -24.54 33 Dunn Stacey 314.33 37 Barker Doug 0.00 88 Smith Dave 258.34 96 Stone Sam 34.98

Fig17_14.cpp (3 of 3)

Because outputLine takes an ostream reference as argument, it can be used with cout (an ostream object) or ofstream object (derived from ostream) to output to the screen or to a file.

Page 61: Chapter 17 File Processing Chapter 17 File Processing

注意事項注意事項使用 fstream 物件可以同時對檔案進行讀或寫

。不要忘記每當讀或寫,都會移動檔案指標,指

向下一個讀或寫的位置。利用該物件的 seekp() 可以根據目前指標的位

置移前或移後。◦ 重要!!

一旦讀到檔尾( eof )時,一定要呼叫該物件的 clear() 成員函式,才能再繼續存取該檔案。 每當遇到 eof ,就會開啟物件中的一個位元(用來紀錄是否已經遇到檔尾

),隨後的動作皆會參考該位元來決定檔案是否讀寫到最後; clear() 主要用來將所有的狀態位元回復為初始狀態。沒有呼叫 clear() 而重新搜尋檔案,會發生檔案指標永遠停到結尾的問題。

Page 62: Chapter 17 File Processing Chapter 17 File Processing

指出以下程式碼可能的錯誤指出以下程式碼可能的錯誤 fstream file(“test.txt”, ios::in | ios::out); int count=0; … file.read((reinterpret_case <char *> &file, sizeof (ClientData))); while (!file) { cout << file.id << firstname << lastname << balance << endl; file.read((reinterpret_case <char *> &file, sizeof (ClientData))); }_____________________________________________while (!file) { int number; cin >> number; file.seekp((number-1)*sizeof(CleantData), ios:: beg); … } …