Download presentation
Presentation is loading. Please wait.
1
第2章 文件操作 陈哲 副教授 南京航空航天大学 计算机科学与技术学院
2
2.1 文件的基本概念 文件是数据的集合,通常存储在磁盘上,便于以后使用;
2.1 文件的基本概念 文件是数据的集合,通常存储在磁盘上,便于以后使用; 几乎所有的程序都用文件存储信息,如:数据库管理系统、操作系统、编译器等; 所有文件都有名字。
3
2.2 使用文件的过程 使用文件分为三步. 1. 必须打开文件 2. 对文件进行读或者写操作 3. 文件操作结束时关闭文件
4
文件流类型 #include <fstream> ofstream:输出文件流 ifstream: 输入文件流
在对文件进行读写之前,必须正确设置. #include <fstream> ofstream:输出文件流 ifstream: 输入文件流 fstream : 文件流
5
2.2.1 文件打开 在对文件进行读或写操作之前必须先打开文件。 ifstream inputFile;
文件打开 在对文件进行读或写操作之前必须先打开文件。 ifstream inputFile; inputFile.open( "d:\\customer.dat "); char fileName[20]; cin>>fileName; inputFile.open(fileName);
6
2.2.1 文件打开(续) 使用fstream 对象时, 第二个参数用于表明文件的打开方式 . Example:
文件打开(续) 使用fstream 对象时, 第二个参数用于表明文件的打开方式 . Example: dataFile.open("info.dat", ios::out);
7
注意: ifstream:只能用于从文件中读取数据,ofstream:只能用于向文件写数据 但可以简单地改变这种方式. For example: Output.open("values.dat", ios::in | ios::binary);
8
注意: ios::app 追加模式 ios::ate 如果已存在,直接转到文件尾部 ios::binary 二进制方式
ios::in 从文件中读数据 ios::out 向文件中写数据 ios::trunc 若文件存在,删除其内容
9
2.2.1 打开文件(续) 先定义流对象,再打开文件 fstream dataFile;
打开文件(续) 先定义流对象,再打开文件 fstream dataFile; dataFile.open("info.dat", ios::in | ios::out); dataFile.open("info.dat", ios::out | ios::app)
10
2.2.1 打开文件(续) fstream dataFile( "names.dat", ios::in | ios::out );
打开文件(续) 2. 定义流对象时打开文件 fstream dataFile( "names.dat", ios::in | ios::out );
11
测试文件打开是否成功 dataFile.fail( ) 测试open函数打开文件是否成功?例如: ifstream dataFile;
dataFile.open("cust.dat", ios::in); if ( ! dataFile ) { cout << "打开文件失败.\n"; exit(0); } dataFile.fail( )
12
2.2.5 关闭文件 当程序不再使用文件时,应关闭文件 1. 文件缓冲区是一块小的内存空间 2. 操作系统限制同时打开的文件数量
关闭文件 当程序不再使用文件时,应关闭文件 1. 文件缓冲区是一块小的内存空间 2. 操作系统限制同时打开的文件数量 Example: dataFile.close( );
13
2.3.1 使用 << 写文件 使用 << 向一个文件写入信息。 例2-2.
使用 << 写文件 使用 << 向一个文件写入信息。 例2-2. #include <iostream> using namespace std; #include <fstream> #include <cstdlib> int main( ) { fstream dataFile ; dataFile.open("demofile.txt", ios::out );
14
cout << "Error opening file.\n"; exit(0); }
if ( ! dataFile ) { cout << "Error opening file.\n"; exit(0); } dataFile << "Confucius\n" ; dataFile << "Mo-tse\n" ; dataFile.close( ); dataFile.open("demofile.txt", ios::out | ios::app); dataFile << "Einstein\n" ; dataFile << "Shakespeare\n" ; return 0; 2-2.cpp
15
2.3.2 文件格式化输出 #include <iostream> #include <fstream>
文件格式化输出 文件格式化输出可以像屏幕格式化输出一样. 例2-5. #include <iostream> #include <fstream> #include <iomanip> using namespace std;
16
fstream outFile("numbers.txt", ios::out );
int main( ) { fstream outFile("numbers.txt", ios::out ); int nums[3][3] = { 1234, 3, 567, 34, 8, 6789, 124, 2345, 89 } ; for( int row = 0 ; row < 3 ; row++ ) // 向文件输出三行 for( int col = 0 ; col < 3 ; col++ ) outFile << setw(10) << nums[row][col] <<" " ; outFile << endl ; } outFile.close( ); return 0; 2-5.cpp
17
2.3.3 采用 >> 从文件读数据 #include <iostream>
采用 >> 从文件读数据 例2-6 #include <iostream> using namespace std; #include <fstream> #include <cstdlib> void main( ) { fstream dataFile; char name [81];
18
dataFile.open("demofile.txt", ios::in); if ( !dataFile) {
cout << "File open error!" << endl; exit(0); } for(int count = 0; count < 4; count++) dataFile >> name; cout << name << endl; dataFile.close( ); 2-6.cpp
19
2.3.4 检测文件结束 while( ! inFile.eof ( )) inFile >> var;
检测文件结束 eof ( ) 成员函数报告文件结尾。 Note: “end of file” 意味着文件指针已经超出了最后一个数据的范围,无数据可读. while( ! inFile.eof ( )) inFile >> var; if (inFile. eof ( )) inFile.close( );
20
while( ! dataFile.eof( )) dataFile >> name ;
例2-7 对例2-6 的改进。 void main( ) { …… // open file while( ! dataFile.eof( )) dataFile >> name ; if(dataFile.fail( )) break; cout << name << "\n"; } dataFile.close( ); 注意:可以将while循环中的 ! dataFile.eof( ) 修改为 true。 2-7.cpp
21
2.4 流对象做参数 Why? 文件流对象可以传递给函数, 但是必须通过引用的方式传递。 例2-8.
2.4 流对象做参数 文件流对象可以传递给函数, 但是必须通过引用的方式传递。 例2-8. #include <iostream> using namespace std; #include <fstream> #include <cstdlib> #include <cstring> bool openFileIn(fstream &, char[ ]); void showContents(fstream &); Why?
22
void main( ) { fstream dataFile; if (!openFileIn(dataFile,"demofile.txt")) { cout << "File open error!" << endl; exit(0); } showContents(dataFile); dataFile.close( );
23
bool openFileIn(fstream &file, char name[ ])
{ file.open(name, ios::in); return file.fail( )? false:true; } void showContents(fstream &file) { char name [81]; while( !file.eof( )) { file >> name ; if(file.fail( )) break; cout << name << " " ; 2-8.cpp
24
2.5 出错检测 流对象的标志位指明了流对象当前状态。 当遇到了输入流的尾部时,设置该位。 ios::eofbit 当操作失败时,设置该位。
2.5 出错检测 流对象的标志位指明了流对象当前状态。 ios::eofbit 当遇到了输入流的尾部时,设置该位。 ios::failbit 当操作失败时,设置该位。 ios::hardfail 当出现不可恢复错误时,设置该位。 ios::badbit 当出现无效操作时,设置该位。 ios::goodbit 当上述所有标记都未设置时,设置该位,表明流对象处于正常状态。
25
2.12出错检测 (续) 这些状态位可以通过函数成员进行检测: eof( )
如果设置了eofbit状态位,该函数将返回true,否则返回false。 fail( ) 如果设置了failbit或hardfail状态位,该函数将返回true,否则返回false。 bad( ) 如果设置了badbit状态位,该函数将返回true,否则返回false。 good( ) 如果设置了goodbit状态位,该函数将返回true,否则返回false。 clear( ) 调用该函数,将清除所有状态位
26
#include <iostream> #include <fstream>
【例2-9】测试文件的几个状态位。 #include <iostream> #include <fstream> using namespace std; void showState( fstream & ); void main( ) { int num= 10 ; fstream testFile("stuff.dat", ios::out ); if( testFile.fail( )) { cout << "打开文件失败! \n" ; exit( 0 ); } cout << "向文件中写数据! \n" ; 2-9.cpp
27
testFile << num ;
showState( testFile ); testFile.close( ); testFile.open("stuff.dat", ios::in); if( testFile.fail( )) { cout << "打开文件失败! \n" ; exit( 0 ); } testFile >> num ;
28
void showState( fstream &file )
{ cout << "当前文件的状态位如下:\n" ; cout <<" eof bit: "<< file.eof( ) << " " ; cout <<" fail bit: "<< file.fail( ) << " " ; cout <<" bad bit: "<< file.bad( ) << " " ; cout <<" good bit: "<< file.good( ) << endl ; file.clear( ); // 清除出错标记位 }
29
2.6 采用函数成员读写文件 采用 >> 读文件的缺陷:空白字符是数据之间的分界符,采用>>操作符进行读取时,就会略过空白字符。 getline 成员函数: dataFile.getline(str, 81, '\n'); (1) str: 从文件中读取的数据将存储在该空间中。 (2) 81: 从文件中最多能读取80个字符。 (3) ‘\n’ 界符。如果在读满最大字符个数之前,遇到了界符,那么将停止读取(注意:该参数可选)。
30
#include <iostream> using namespace std;
#include <fstream> #include <cstdlib> void main( ) { fstream readFile ; char input[81] ; readFile.open("numbers.txt", ios::in ); if(readFile.fail( )) cout << "打开文件失败!" << endl ; exit( 0 ); } 2-11.cpp
31
// use '\n' as a delimiter while( ! readFile.eof( )) { readFile.getline(input,81); if(readFile.fail( )) break; cout << input << endl ; } readFile.close( );
32
2.6 采用函数成员读写文件 (续) get 成员函数: 每次从文件读取一个字符。 inFile.get(ch);
2.6 采用函数成员读写文件 (续) get 成员函数: 每次从文件读取一个字符。 inFile.get(ch); put成员函数: 每次向文件写入一个字符。 outFile.put(ch); 例2-13 的修改版 #include <iostream> #include <fstream> using namespace std;
33
int main( ) // 思考如下程序的功能
{ fstream dataFile("sentences.txt", ios::out); char ch; while( cin.get(ch) ) { if(ch == '!' ) break ; dataFile.put(ch); } dataFile.close( ); return 0; ? 从键盘上读取数据,一边读一边写,遇到点停止,并且将点写到文件中。 2-13.cpp
34
2.7 多文件操作 程序中可能同时打开多个文件。 例2-14要求用户输入文件名,打开文件并读取数据,将每个字符转换为大写,然后写到另一个输出文件out.txt中。
35
#include <iostream>
using namespace std; #include <fstream> #include <cstdlib> #include <cctype> int main( ) { ifstream inFile; ofstream outFile("out.txt"); char fileName[81], ch, ch2; cout << "请输入文件名: "; cin >> fileName; inFile.open(fileName);
36
{ cout << "打开失败" << fileName << endl; exit(0); }
if (!inFile) { cout << "打开失败" << fileName << endl; exit(0); } while( !inFile.eof( )) { inFile.get(ch); if ( inFile.fail( )) break; ch2 = toupper(ch); outFile.put(ch2); inFile.close( ); outFile.close( ); 2-14.cpp
37
2.8 二进制文件 ofstream file("num.dat"); int x = 1297; file << x;
2.8 二进制文件 二进制文件中存储的数据是非格式化的,按照在内存中存储的形式存储,不是按照ASCII纯文本方式存储。 Example: ofstream file("num.dat"); int x = 1297; file << x; 存储形式是: ' 1 ', ' 2 ', ' 9 ', ' 7 '.
38
2.8 二进制文件 以二进制方式打开文件: file.open("stuff.dat", ios::out | ios::binary);
2.8 二进制文件 以二进制方式打开文件: file.open("stuff.dat", ios::out | ios::binary); Note: 缺省情况下文件是以文本方式打开. 读/写函数: file.write ((char *)buffer, sizeof (buffer)); file.read ((char *)buffer, sizeof (buffer));
39
#include <iostream> #include <fstream>
程序举例:例2-15 #include <iostream> #include <fstream> #include <iomanip> using namespace std; void main( ) { fstream file; int buffer[10] = {1,2,3,4,5,6,7,8,9,10 };
40
file.open("a1.txt", ios::out | ios::binary);
// 创建一个二进制文件 file.open("a1.txt", ios::out | ios::binary); file.write ((char*)buffer, sizeof (buffer)); file.close( ); file.open("a1.txt", ios::in | ios::binary); file.read ((char*)buffer, sizeof(buffer)); for(int count = 0; count < 10; count++) cout << setw(6)<<buffer[count]; // 创建一个文本文件 file.open("a2.txt", ios::out); for(int i = 0; i < 10; i++) file<<buffer[i]; } 思考:每个文 件的大小? 2-15.cpp
41
2.8.2 读写结构体记录 结构体数据可以采用定长块存储到文件中。
读写结构体记录 结构体数据可以采用定长块存储到文件中。 Note: 因为结构体包含不同类型的数据,所以当打开文件时必须以二进制方式打开。 例2-16.
42
#include <iostream>
using namespace std; #include <fstream> #include <cstdlib> #include <cctype> struct Info { char name[21] ; int age ; char address[51] ; char phone[14] ; char [51] ; } ;
43
int main( ) { fstream people("people.dat", ios::out | ios::binary); Info person ; char again ; if(people.fail( )) cout << "打开文件people.dat出错! \n" ; exit( 0 ); }
44
do { cout << "请输入下面的数据: \n" ; cout << "姓名: " ; cin.getline(person.name, 21); cout << "年龄: " ; cin >> person.age ; cin.ignore( ); // 略过换行符, why? cout << "联系地址: " ; cin.getline(person.address, 51); cout << "联系电话: " ; cin.getline(person.phone, 14); cout << " " ; cin.getline(person. , 51); people .write(( char *)&person, sizeof(person)); cout << "还要再输入一个同学的数据吗 ? " ; cin >> again ; cin.ignore( ); } while( toupper( again ) == 'Y' ); people.close( ); // 关闭文件
45
// 下面是再次打开文件进行读取数据 cout << "\n\n*** 下面显示所有人的数据 ***\n" ; people.open("people.dat", ios::in | ios::binary); if(people.fail( )) { cout << "打开文件people.dat出错! \n" ; exit( 0 ); }
46
people.read(( char *)&person, sizeof(person));
while( !people.eof( )) { people.read(( char *)&person, sizeof(person)); if(people.fail( )) break; cout << "姓名: " << person.name << endl ; cout << "年龄: " << person.age << endl ; cout << "地址: " << person.address << endl ; cout << "电话: " << person.phone << endl ; cout << " " << person. << endl ; cout << "\n按任意键,显示下一个记录!\n" ; cin.get(again); } cout << "显示完毕 ! \n" ; people.close( ); return 0; 2-16.cpp
47
2.9 随机访问文件 顺序访问文件和随机访问文件就像磁带和CD之间的区别。
2.9 随机访问文件 顺序访问文件和随机访问文件就像磁带和CD之间的区别。 seekp 和 seekg 函数: seekp 函数用于输出文件(写) ,seekg 函数用于输入文件(读)。 Example: file.seekp (20L, ios::beg);
48
2.9 随机访问文件(续) 表 2-6 列出了文件随机访问模式. ios::beg 从文件头开始计算偏移量. ios::end
2.9 随机访问文件(续) 表 2-6 列出了文件随机访问模式. ios::beg 从文件头开始计算偏移量. ios::end 从文件尾开始计算偏移量. ios::cur 从当前位置开始计算偏移量.
49
2.9 随机访问文件(续) Examples: file.seekp (2L, ios::beg);
2.9 随机访问文件(续) Examples: file.seekp (2L, ios::beg); file.seekp (-1L, ios::end); file.seekp (2L, ios::cur); file.seekg (2L, ios::beg); file,seekg (-1L, ios::end); file.seekg (4L, ios::cur); file.seekg (0L, ios::end);
50
内容:123456789 #include <iostream> #include <fstream>
using namespace std; void main( ) { fstream file("digit.txt ",ios::in); char ch; if (!file) exit(0); file.seekg (1L, ios::beg); file.get(ch); cout << ch << endl; file.seekg (-3L, ios::end); file.seekg (1L, ios::cur); file.close( ); } 内容: 如果内容是1-9,那么输出结果是2,7,9 2-17.cpp
51
2.9 随机访问文件(续) tellp 和 tellg 函数 : tellp 用于返回写位置,tellg用于返回读位置. Example:
2.9 随机访问文件(续) tellp 和 tellg 函数 : tellp 用于返回写位置,tellg用于返回读位置. Example: pos1 = outFile.tellp( ); pos2 = inFile.tellg( ); 例2-19:
52
#include <iostream>
using namespace std; #include <fstream> #include <cstdlib> #include <cctype> void main( ) { fstream file("digit.txt", ios::in); long offset; char ch, again; if(!file) exit(0);
53
cout << "当前位置为: "<< file.tellg( )<<endl;
do { cout << "当前位置为: "<< file.tellg( )<<endl; cout << "输入一个偏移量 : "; cin >> offset; file.seekg(offset, ios::beg); file.get(ch); cout << "读取的字符是: "<< ch << endl; cout << "是否继续 ? "; cin >> again; } while (toupper(again) == 'Y'); file.close(); } 2-19.cpp
54
2.10 输入输出二进制文件综合举例 不关闭和重新打开文件的情况下,同时执行输入和输出。 Example:
2.10 输入输出二进制文件综合举例 不关闭和重新打开文件的情况下,同时执行输入和输出。 Example: fstream file("data.dat", ios::in | ios::out); file.open("data.dat", ios::in | ios::out); file.open("data.dat", ios::in|ios::out|ios::binary); 例:2-20 2-20.cpp
55
#include <iostream>
#include <fstream> #include <iomanip> using namespace std; struct Info // 定义一个结构体 { char name[21] ; int age ; char address[51] ; char phone[14] ; char [51] ; } ; void createFile(fstream & ); void editFile(fstream & ); void showFile(fstream & ); void main( ) { int choice; fstream people("Info.dat", ios::in | ios::out | ios::binary); if( people.fail( )) exit( 0 );
56
while( true ) { cout<<"\n\t 1. Create 2.Show 3.Edit 4.Exit\n"; cin>>choice; switch( choice ) { case 1: createFile(people ); break; case 2: showFile(people ); case 3: editFile(people ); case 4: exit( 0 ); } people.close( );
57
// 下面的createFile函数采用5个空记录设置文件
void createFile( fstream & file ) { Info record={"",0,"","",""}; for(int count = 0; count < 5; count++ ) cout << "写记录: " << count << endl; file.write((char *)&record, sizeof(record)); } //file.flush( );
58
// showFile函数显示文件的内容 void showFile(fstream & file ) { Info person={"",0,"","",""} ; file.clear( ); // 清除各标记 file.seekg( 0L,ios::beg); while( !file.eof( )) { file.read(( char *)&person, sizeof(person)); if(file.fail( )) break; cout << "姓名: " << person.name; cout << setw(20)<< "年 龄: " << person.age ; cout <<setw(20)<< "地址:" <<person.address<< endl; cout << "电话: " << person.phone ; cout << setw(21)<< " " << person. << endl ; }
59
// 下面的函数通过调整写指针,可以修改任意一个记录
void editFile(fstream & file ) { Info person ; long recNum ; file.clear( ); cout << "你想修改哪个人(0 - 4) ? " ; cin >> recNum ; cin.ignore( ); // 略过后面的换行符 file.seekg(recNum * sizeof(person), ios::beg); file.read(( char *)&person, sizeof(person)); cout << "姓名: " << person.name; cout << setw(20)<< "年 龄: " << person.age ; cout << setw(20)<< "地址: " << person.address<< endl; cout << "电话: " << person.phone ; cout << setw(21)<< " " << person. << endl ;
60
// 输入新数据 cout << "请输入下面的新信息: \n" ; cout << "姓名: " ; cin.getline(person.name, 21); cout << "年龄: " ; cin >> person.age ; cin.ignore( ); // 略过换行符 cout << "联系地址: " ; cin.getline(person.address, 51); cout << "联系电话: " ; cin.getline(person.phone, 14); cout << " " ; cin.getline(person. , 51); file.seekp( recNum * sizeof(person), ios::beg); file.write(( char *)&person, sizeof(person)); file.flush( ); }
Similar presentations