Download presentation
Presentation is loading. Please wait.
1
第八章 文件 引述 输入输出流和文件概述 文件操作 流的格式化输出 程序举例 本章小节
2
8.1 引述 任务8.1 从键盘输入40位学生的信息,将其存储到磁盘文件
8.1 引述 任务8.1 从键盘输入40位学生的信息,将其存储到磁盘文件 任务8.2 从任务8.1建立的磁盘文件中读取学生信息,将其存放到结构数组并输出。 算法分析: 要解决这两个问题,主要是要解决学生信息的存储和读取问题,即如何使用C语言,将一些信息存入到一个磁盘文件中,然后从磁盘文件中读取信息并存放到数组中。为此需要用到C语言的文件这一数据类型。
3
8.2.1 输入输出流概述 文本流(text stream)又称文字流或字符流 文本流是一个个的字符,用换行符表示一行的结束。
文本流文件的信息直接可见 利用文本流只能读写文本文件 二进制流(binary stream) 又称字节流 二进制流则由一系列字节组成 字节流文件信息一般不能直接可见 用于对声音、图像等非文本文本进行读写 cin和cout实际上都是文本流
4
8.2.2 文件概述 文件可表示磁盘文件、键盘、显示器等所有的外部设备 C文件常被称为流式文件
流式函数将文件或数据项作为单个字符(或字节)构成的数据流来处理 流式函数在读写流式文件的数据时采用了缓冲存储区域,可以一次传输大量数据,提高了输入输出的效率 缓冲存储技术用于解决内存、外存读写速度差异很大的问题
5
8.3.1 文件的打开和关闭 头文件fstream ifstream:输入流,用于读文件 ofstream:输出流,用于写文件
ifstream fin(filePath); //打开字符文件用于读 ifstream fin(filePath,ios::binary); //打开字节文件用于读 ofstream fout(filePath); //打开字符文件用于写 ofstream fout(filePath,ios::binary);//打开字节文件用于写 ifstream file; file.open(filePath, ios::binary); //打开字节文件用于读
6
8.3.1 文件的打开和关闭 文件打开模式 模式参数 模式含义 ios::in 读 ios::out 写 ios::app 从文件末尾开始写
ios::binary 二进制模式 ios::nocreate 打开文件时,若文件不存在,不创建 ios::noreplace 打开文件时,若文件不存在,则创建 ios::trunc 打开一个文件,然后清空内容 ios::ate 打开一个文件时,将位置移动到文件尾 参数用|(按位与)操作符进行连接 fstream file; file.open(filePath, iso::in|ios::out); // 打开字符文件用于读写
7
8.3.1 文件的打开和关闭 测试文件是否正确打开 if(!file) { // 文件打开失败 } 关闭文件 file.close();
8
8.3.2 字符流文件的输入和输出 1. 字符流文件的输出 与cout类似,使用插入运算符<< 任务8.1 算法
9
8.3.2 字符流文件的输入和输出 任务8.1 核心程序——打开文件,读入学生信息
ofstream fout(“student.txt”);// 打开字符文件用于写 if(!fout) { cout<<"文件打开失败!"<<endl; return -1; // 返回错误代码-1 } for(i = 1; i <= n; i++) // 循环输入学生信息 cout<<"请输入第"<<i<<" 位学生信息:"<<endl; stuList[i] = readStudent();
10
8.3.2 字符流文件的输入和输出 任务8.1 核心程序——学生信息写入文件
for(i = 1; i <= n; i++) // 循环将学生信息写入文件 { fout<<"姓名 "<<stuList[i].name<<endl; fout<<"学号 "<<stuList[i].no<<endl; fout<<"性别 " <<(stuList[i].sexy==1?"男":"女")<<endl; fout<<"生日 "<<stuList[i].birthday.year<<"-" <<stuList[i].birthday.month<<"-" <<stuList[i].birthday.day<<endl; fout<<"身高 "<<stuList[i].height<<endl; fout<<"体重 "<<stuList[i].weight<<endl; fout<<"电话 "<<stuList[i].telephone<<endl; fout<<"E_mail "<<stuList[i].e_mail<<endl; fout<<"QQ号 "<<stuList[i].qq<<endl; } fout.close(); // 关闭文件
11
8.3.2 字符流文件的输入和输出 1. 字符流文件的输出 生成的文本文件示例
12
8.3.2 字符流文件的输入和输出 2. 字符流文件的输入 任务8.2 算法分析 与cin类似,使用析取运算符>>
读入一行,使用成员函数getline fin.getline(字符数组名, 最大字符长度); fin.getline(stuList[i].name, 20); //从文件读取当前行的最多20字符到stuList[i]的name成员中 成员函数eof()判断整个文件的读取是否已经完成,如果读取完成,这个函数将返回真
13
8.3.2 字符流文件的输入和输出 2. 字符流文件的输入 任务8.2 核心程序——从文本文件中读取数据
while(!fin.eof()) // 循环读取文件,至读到文件结束为止 { fin>>propertyName; // 读入姓名行的属性名称 if(strcmp(propertyName, "姓名") != 0) { // 未读到姓名,转向读入下一行内容 continue; } n++; // 开始读取第n位同学的信息 fin.getline(stuList[n].name, 20); fin>>propertyName;// 读入学号行的属性名称 fin.getline(stuList[n].no, 20); fin>>propertyName;// 读入QQ行的属性名称 fin.getline(stuList[n].qq, 20);
14
8.3.2 字符流文件的输入和输出 2. 字符流文件的输入 任务8.2 核心程序——从文本文件中读取数据
while(!fin.eof()) // 循环读取文件,至读到文件结束为止 { fin>>propertyName; // 读入姓名行的属性名称 if(strcmp(propertyName, "姓名") != 0) { // 未读到姓名,转向读入下一行内容 continue; } n++; // 开始读取第n位同学的信息 fin.getline(stuList[n].name, 20); fin>>propertyName;// 读入学号行的属性名称 fin.getline(stuList[n].no, 20);
15
8.3.2 字符流文件的输入和输出 2. 字符流文件的输入 任务8.2 核心程序——从文本文件中读取数据
fin>>propertyName; // 读入性别行的属性名称 fin.getline(propertyValue, 20); if(strstr(propertyValue, "男") >= 0) { stuList[n].sexy = 1; } else stuList[n].sexy = 0; fin>>propertyName; // 读入生日行的属性名称 stuList[n].birthday = str2date(propertyValue);
16
8.3.2 字符流文件的输入和输出 2. 字符流文件的输入 任务8.2 核心程序——输出数据 fin.close(); // 关闭输入文件
cout<<"从文件读入的学生信息:"<<endl; writeStudentInfoTitle(); // 输出学生信息标题行 for(i = 1; i <= n; i++) // 逐行输出学生信息 { writelnStudent(stuList[i]); } writeStudentInfoTail(); // 输出学生信息尾部行 cout<<"\t\t共有"<<n<<" 位学生"<<endl;
17
8.3.3 字节流文件的输入和输出 1. 字节流文件的输出 任务8.1 算法分析 打开文件时,需要使用ios::binary模式申明
write成员函数:用于向文件写入变量的内容 fout.write((char *)(&变量名), sizeof(变量名)); 前一参数为要写入文件的变量的地址,需转换为char *类型 后一参数为变量所占用的字节数 任务8.1 算法 以字节流方式打开一个文件,命名为student.dat,用于写 然后依次输入学生信息, 再使用write成员函数将其写入文件
18
8.3.3 字节流文件的输入和输出 1. 字节流文件的输出 任务8.1 核心程序——写入数据至文件
ofstream fout("student.dat", ios::binary); // 以字节流方式打开文件student.data用于写 if(!fout) { cout<<"文件打开失败!"<<endl; return -1; // 返回错误代码-1 } for(i = 1; i <= n; i++) { // 循环将学生信息写入文件 fout.write((char *)(stuList+i), sizeof(StudentInfo)); fout.close(); // 关闭文件
19
8.3.3 字节流文件的输入和输出 1. 字节流文件的输出 任务8.1 算法分析
fout.write((char *)(stuList+i), sizeof(StudentInfo)); 一条语句就完成了信息的写入操作,更加简单; 而且就算学生信息结构体发生了变化,比如增加或减少了属性,这条语句也可以不作修改,程序的可重用度更高 文件是不能直接读的,所以安全性更高一些
20
8.3.3 字节流文件的输入和输出 2. 字节流文件的输入 任务8.2 算法分析 打开文件时,需要使用ios::binary模式申明
read成员函数,用于文件中读取数据 fin.read((char *)(&变量名), sizeof(变量名)); 任务8.1 算法 指定文件中读入学生信息至数组的程序封装为函数,有三个参数 存储学生信息的结构数组, 读入到的学生人数,设为传引用 文件名
21
8.3.3 字节流文件的输入和输出 2. 字节流文件的输入 任务8.2 核心程序
void freadStudents(StudentInfo stuList[], int &nStudent, char fileName[]) { // 首先打开文件 while(!fin.eof())// 循环读取文件,至读到文件结束为止 nStudent++; // 当前学生序号增1 fin.read((char *)(stuList+nStudent), sizeof(StudentInfo)); if(strlen(stuList[nStudent].name) < 1) { // 如果读入的学生姓名为空,则忽略之 nStudent--; } fin.close(); // 关闭输入文件
22
8.3.3 字节流文件的输入和输出 3. 字符流文件和字节流文件的比较
使用字节流方式对记录信息进行读写时,操作比字符流方式更简单一些,文件安全性更高, 所以,对文件进行操作时,一般使用字节流方式进行读写。 要求文件可以直接查看,使用字符流方式读写
23
8.4 流的格式化输出 格式控制函数 行内格式的控制
24
8.4 流的格式化输出 任务8.3 编写函数将多位学生的信息以表格方式输出 算法分析: 设多位学生的信息存储在一个学生信息结构数组中,
用一个整型变量存储学生人数,两者一并传入函数。 在函数中,首先输出表头信息,然后依次以上图所示格式输出学生信息,最后输出表格的结尾行及学生人数信息即可。 关键是如何控制输出格式,使不同长度的信息能以规范的格式进行输出
25
8.4.1 格式控制函数 cout.setf(控制标志); // 设置输出流的格式控制标志 控制标志 标志含义 ios::dec
将整数以10进制输出 ios::hex 将整数以16进制输出 ios::oct 将整数以8进制输出 ios::showbase 显示进制标志(0为8进制,0x为16进制) ios::left 左对齐 ios::right 右对齐 ios::internal 符号左对齐,数值右对齐,中间用空格分隔 ios::fixed 浮点数以小数方式输出 ios::scientific 浮点数以科学计数式输出 ios::showpoint 浮点数输出小数点(如1将会输出1.0) ios::showpos 正数前输出+
26
8.4.1 格式控制函数 cout.unsetf(); // 用于取消控制格式 一般同类的输出格式设置后,需要先执行复位,再设置别的格式
cout.unsetf(ios::dec); // 取消以10进制方式输出整数 cout.setf(ios::oct); // 设置以8进制方式输出整数 cout.setf(ios::right); cout.width(5); cout.fill('0'); cout<<123<<“ ”<<123456; // 输出 cout.precision(4); cout<<1.23<<" "<< << <<endl; // 输出 e+006 cout.setf(ios::fixed); // 输出
27
8.4.2 行内格式控制 cout<<单行控制标志<<输出对象; 控制标志 标志含义 dec/hex/oct
将整数以10/16/8进制输出 showbase/unshowbase 显示/不显示进制标志(0为8进制,0x为16进制) left/right 左/右对齐 internal 符号左对齐,数值右对齐,中间用空格分隔 fixed/ scientific 浮点数以小数方式/科学计数式输出 showpoint 强制浮点数输出小数点(如1将会输出1.0) noshowpoint 不强制浮点数输出小数点(如1.0将会输出1) showpos/noshowpos 正数前输出/不输出+ setfill(字符) 设置填充字符 setw(整数) 设置字符串宽度 setprecision(整数) 控制输出流显示浮点数的数字个数,如果和fixed合用,则用于控制小数点右边的位数。
28
8.4.2 行内格式控制 cout<<showbase<<oct<<123<<" "<<noshowbase <<hex<<123<<endl; cout<<showpos<<dec<<123<<" "<<noshowpos<<123<<endl; cout<<showpoint<<123.0<<" "<<noshowpoint<<123.0<<endl; cout<<setprecision(4)<<fixed<<1.23<<" "<< << <<endl; 输出结果: 0173 7b 行内格式控制比成员函数的使用更简单,使用更普遍
29
8.4.2 行内格式控制 任务8.3 核心程序 cout.setf(ios::left); // 设置内容左对齐
cout.fill(' '); // 位数不足时,以空格填充 cout<<showpoint; // 输出浮点数时显示小数点 cout<<setprecision(3); // 浮点数精度为3位 cout<<" | "; cout<<setw(13)<<stuList[i].no<<"| "; cout<<setw(17)<<stuList[i].name<<"| "; cout.setf(ios::right); // 设置内容右对齐 cout<<setw(4)<<stuList[i].birthday.year<<"年" <<setw(2)<<stuList[i].birthday.month<<"月" <<setw(2)<<stuList[i].birthday.day<<"日|"; cout<<" "<<(stuList[i].sexy==1?"男":"女")<<" "<<"| "; cout<<setw(4)<<stuList[i].height<<" | "; cout<<setw(4)<<stuList[i].weight<<" |"; cout.unsetf(ios::right);// 取消设置内容右对齐 cout<<endl;
30
8.6 本章小节 1. 流是一个字符或字节序列,无论是输入操作还是输出操作,都是控制这个字符或字节序列。
2. 流可以使用相同的操作方式对不同的数据类型进行不同的操作,如cin均使用>>连接不同的输入对象,C语言自行决定对不同类型的数据进行不同的输入操作,因此十分方便。 3. C的流式文件是有序的字符流或字节流,文件必须先打开,再使用。使用完成后,必须关闭。 4. C的字符流文件的输入输出方式与cin和cout的使用方式基本相同。 5. 字节流文件可以将一个结构变量整体存储或读入,当存储的数据较复杂时,使用它比使用字符流文件更加方便。 6. 可以使用流的格式控制成员函数或控制标识符,对数据的输出格式如数据的占位宽度、对齐方式、浮点数的精度、整数的进制等进行设置。这些成员函数和控制标识是定义在头文件iomanip中的,使用前需先使用预处理命令#include。
Similar presentations