一、输入输出流(I/O strea)
编译系统已经以运算符或函数的形式做好了对标准外设(键盘、屏幕、打印机、文件)的接口,使用时只需按照要求的格式调用即可。
cin>>x; cout<<x; cin.get(ch);
C++语言的I/O系统向用户提供一个统一的接口,使得程序的设计尽量与所访问的具体设备无关,在用户与设备之间提供了一个抽象的界面:输入输出流。
【重载输入(提取)和输出(插入)运算符】
用标准流进行输入/输出时,系统自动地完成数据类型的转换。对于输入流,要将输入的字符序列形式的数据变换成计算机内部形式的数据(二进制或ASCII)后,再赋给变量,变换后的格式由变量的类型确定。对于输出流,将要输出的数据变换成字符串形式后,送到输出流(文件)中。
示例:===
在C++中允许用户重载运算符“<<”和“>>”,实现对象的输入和输出。重载这二个运算符时,在对象所在的类中,将重载这二个运算符的函数说明该类的友元函数。
重载(提取)运算符的一般格式为:
返回值类型:类istream的引用,cin中可以连续使用运算符“>>”。
- 第一个参数:是“>>”的左操作数cin类型,类istream的引用。
- 第二个参数:是“>>”的右操作数,即欲输入的对象的引用。
示例:
#include <iostream>
using namespace std;class InCount
{
public:InCount(int a = 0, int b = 0){c1 = a;c2 = b;}void show(void){cout << "c1=" << c1 << "\t" << "c2=" << c2 << endl;}friend istream& operator>>(istream&, InCount&);friend ostream& operator<<(ostream&, InCount&);private:int c1, c2;
};istream& operator>>(istream& is, InCount& cc)
{is >> cc.c1 >> cc.c2;return is;
}ostream& operator<<(ostream& os, InCount& cc)
{os << "c1=" << cc.c1 << "\t" << "c2=" << cc.c2 << endl;return os;
}int main()
{InCount obj1, obj2;cout << obj1 << obj2 << endl; // 调用输出函数cin >> obj1;cin >> obj2;cout << obj1 << obj2;return 0;
}
二、文件流
C++在头文件fstream.h中定义了C++的文件流类体系 ,当程序中使用文件时,要包含头文件fstream.h。
当使用文件时,在程序头有:#include<fstream.h>。其中定义了各种文件操作运算符及函数。
程序对文本文件的操作与对键盘、显示器的操作比较:
在涉及文本文件的操作时,将输入文件看成键盘,将输出文件看成显示器,格式不变。只需在程序中增加打开与关闭文件的语句。
【文件的操作】
C++标准库专门提供了3个类用于实现文件操作,它们统称为文件流类,这3个类分别为:
- ifstream:专用于从文件中读取数据;
- ofstream:专用于向文件中写入数据;
- fstream:既可用于从文件中读取数据,又可用于向文件中写入数据。
【fstream类常用成员方法】
示例:
#include <iostream>
#include <fstream>
using namespace std;int main()
{const char* str = "http://www.163.com";// 我们要创建一个fstream类的对象fstream fs;// 将demo.txt文件和fs文件流建立关联fs.open("demo.txt", ios::out);fs.write(str, 100);fs.close();return 0;
}
打开文件可以通过以下两种方式进行:
- 调用流对象的 open 成员函数打开文件。
- 定义文件流对象时,通过构造函数打开文件。
【使用 open 函数打开文件】
先看第一种文件打开方式。以 ifstream 类为例,该类有一个 open 成员函数,其他两个文件流类也有同样的 open 成员函数:
void open(const char* szFileName, int mode)
第一个参数是指向文件名的指针,第二个参数是文件的打开模式标记。
【文件打开模式标记】
ios::binary 可以和其他模式标记组合使用,例如:
- ios::in | ios::binary表示用二进制模式,以读取的方式打开文件;
- ios::out |ios::binary表示用二进制模式,以写入的方式打开文件。
在流对象上执行 open 成员函数,给出文件名和打开模式,就可以打开文件。判断文件打开是否成功,可以看“对象名”这个表达式的值是否为 true,如果为 true,则表示文件打开成功。
示例:
#include <iostream>
#include <fstream>
using namespace std;int main()
{//ifstream inFile;//inFile.open(".\\demo.txt", ios::in);//if (inFile) // 条件成立,则说明文件打开成功//{// cout << "\ndemo.txt文件打开成功." << endl;// inFile.close();//}//else//{// cout << "\ndemo.txt文件打开失败." << endl;// return 1;//}//ofstream outFile;//outFile.open(".\\outdemo.txt", ios::out);//if (outFile) // 条件成立,则说明文件打开成功//{// cout << "\noutdemo.txt文件打开成功." << endl;// outFile.close();//}//else//{// cout << "\noutdemo.txt文件打开失败." << endl;//}fstream ioFile;ioFile.open(".\\iodemo.txt", ios::in | ios::out | ios::trunc);if (ioFile){cout << "\niodemo.txt文件打开成功." << endl;ioFile.close();}else{cout << "\niodemo.txt文件打开失败." << endl;}return 0;
}
调用open()方法打开文件,是文件流对象和文件之间建立关联的过程。那么,调用 close()方法关闭已打开的文件,就可以理解为是切断文件流对象和文件之间的关联。
注意,close()方法的功能仅是切断文件流与文件之间的关联,该文件流并会被销毁,其后续还可用于关联其它的文件。
close()方法的用法很简单,其语法格式如下:
void close();
可以看到,该方法既不需要传递任何参数,也没有返回值。
1、【C++ ostream::write()方法写文件】
ofstream 和 fstream 的 write()成员方法实际上继承自 ostream 类,其功能是将内存中 buffer 指向的 count 个字节的内容写入文件,基本格式如下:
ostream & write(char* buffer, int count);
其中,buffer 用于指定要写入文件的二进制数据的起始位置;count 用于指定写入字节的个数。也就是说,该方法可以被 ostream 类的 cout 对象调用,常用于向屏幕上输出字符串。同时,它还可以被 ofstream 或者 fstream 对象调用,用于将指定个数的二进制数据写入文件。
同时,该方法会返回一个作用于该函数的引用形式的对象。举个例子,obj.write() 方法的返回值就是对 obj 对象的引用。
示例:
#include <iostream>
#include <fstream>
using namespace std;class student
{
public:int no;char name[10];int age;
};int main()
{student stu;ofstream outFile("student.dat", ios::out | ios::binary);if (!outFile){cout << "\n打开文件student.txt失败." << endl;outFile.close();}else{cout << "\n打开文件student.txt成功." << endl;}while (cin >> stu.no >> stu.name >> stu.age)outFile.write((char*)&stu, sizeof(stu));outFile.close();return 0;
}
2、【C++ istream::read()方法读文件】
ifstream 和 fstream 的 read()方法实际上继承自 istream 类,其功能正好和 write() 方法相反,即从文件中读取 count个字节的数据。该方法的语法格式如下: istream & read(char* buffer, int count);
其中,buffer 用于指定读取字节的起始位置,count 指定读取字节的个数。同样,该方法也会返回一个调用该方法的对象的引用。
示例:
#include <iostream>
#include <fstream>
using namespace std;class student
{
public:int no;char name[10];int age;
};int main()
{student stu;ifstream inFile("student.dat", ios::in | ios::binary); // 二进制读方式打开此文件 if (!inFile){cout << "\n打开失败." << endl;return 0;}elsecout << "\nstudent.dat文件打开成功." << endl;while (inFile.read((char*)&stu, sizeof(stu))){cout << stu.no << "," << stu.name << "," << stu.age << endl;}inFile.close();return 0;
}
3、【C++ ostream::put()成员方法】
掌握了如何通过执行 cout.put() 方法向屏幕输出单个字符。fstream 和 ofstream 类继承自 ostream 类,因此 fstream 和 ofstream 类对象都可以调用 put() 方法。
当 fstream 和 ofstream 文件流对象调用put() 方法时,该方法的功能就变成了向指定文件中写入单个字符。put() 方法的语法格式如下: ostream& put (char c);
其中,c 用于指定要写入文件的字符。该方法会返回一个调用该方法的对象的引用形式。
示例:
// 009.cpp : 此文件包含 “main” 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <fstream>
using namespace std;int main()
{char ch;ofstream outFile("outdemo.txt", ios::out | ios::binary);if (!outFile){cout << "\noutdemo.txt文件打开失败." << endl;return 0;}elsecout << "\noutdemo.txt文件打开成功." << endl;while (cin >> ch){outFile.put(ch);}outFile.close();return 0;
}
4、【C++ istream::get()成员方法】
与put() 成员方法的功能相对的是 get() 方法,其定义在 istream 类中,借助 cin.get() 可以读取用户输入的字符。在此基础上,fstream 和 ifstream 类继承自 istream 类,因此 fstream 和 ifstream 类的对象也能调用 get() 方法。
当 fstream 和 ifstream 文件流对象调用 get() 方法时,其功能就变成了从指定文件中读取单个字符(还可以读取指定长度的字符串)。这里仅介绍最常用的 2 种:
- int get();
- istream& get (char& c);
其中,第一种语法格式的返回值就是读取到的字符,只不过返回的是它的 ASCII 码,如果碰到输入的末尾,则返回值为 EOF。第二种语法格式需要传递一个字符变量,get() 方法会自行将读取到的字符赋值给这个变量。
示例:
#include <iostream>
#include <fstream>
using namespace std;int main()
{char ch;ifstream inFile("outdemo.txt", ios::out | ios::binary);if (!inFile){cout << "\noutdemo.txt文件打开失败." << endl;return 0;}elsecout << "\noutdemo.txt文件打开成功." << endl;while ((ch=inFile.get())&& ch!=EOF){cout << ch;}inFile.close();return 0;
}
5、【文件指针】
当一打开文件,文件指针位于文件头,并随着读写字节数的多少顺序移动。可以利用成员函数随机移动文件指针。
【随机读取二进制文件】
infile.seekg(int);//将文件指针移动到由参数指定的字节处
infile.seekg(100);//将文件指针移动到距离文件头100个字节处
infile.seekg(100, ios::beg);//移动到距文件头100个字节
infile.seekg(-100, ios::cur);//移动到距当前位置前100个字节
infile.seekg(-500, ios::end);//移动到距文件尾前500个字节