一、文件的概念
内存中存放的数据是在计算机关机后就会消失的,要长久保存数据,就要使用硬盘、光盘、U盘等设备。为了便于数据的管理和索引,引入了“文件”的概念。
一篇文章、一段视频、一个可执行程序,都可以被保存为一个文件,并赋予一个文件名。操作系统以文件为单位管理磁盘中的数据。
成千上万个文件如果不加分类放在一起,用户使用起来显然非常不方便,因此又引入了树形目录(目录也叫文件夹)的机制,可以把文件放在不同的文件夹中,文件夹中还可以嵌套文件夹,这就便于用户对文件进行管理和使用,正如Windows管理器呈现的那样。
一般来说,文件可分为文本文件、视频文件、音频文件、图像文件、可执行文件等多种类别,这是从文件的功能进行分类的。从数据存储的角度来说,左右的文件本质上都是一样的,都是由一个个字节组成的,归根到底都是0、1比特串。不同的文件呈现出不同的形态(有的是文本、有的是视频等),这主要是文件创建者和解释者(使用文件的软件)约定好了文件格式。
所谓“格式”,就是关于文件中每一部分的内容代表什么含义的一种约定。例如,常见的纯文本文件(也叫文本文件,扩展名通常是“.txt”),指的是能够在Windows的“记事本”程序中打开,并且能看出是一段有意义的文字的为念。文本文件的格式可以用一句话来描述:文件中的每一个字节都是一个可见字符的ASCII码。
除了纯文本文件外,图像、视频、可执行文件等一般被称作“二进制文件”。二进制文件如果用“记事本”程序打开,看到的是一片乱码。
所谓“文本文件”和“二进制文件”,只是约定俗成、从计算机用户角度出发进行分类,并不是计算机科学的分类,因为从计算机科学的角度来看,所有的文件都是由二进制组成的,都是二进制文件。文本文件和其他二进制文件只是格式不同而已。
使用文本文件也可以表示图像,例如:
6 4
24 0 38 129 4 154
12 73 227 40 0 0
12 173 127 20 0 0
21 73 87 230 1 0
表示衣服宽度为6像素,高度为4像素的256色图像。
这个“文本图像”文件格式可以描述为:第一行的两个数分别代表水平方向的像素数目和垂直方向的像素数目,此后每行代表图像的一行像素,一行中的每个数对应于一个像素,表示其颜色。理解这一格式的图像处理软件就可以把上述文本文件呈现为一幅图像。视频是由每秒24幅图像组成的,因此用文本文件也可以表示视频。但是用文本表示图像的方法是非常低效的,浪费了太多的空间。
C++文件类
C++标准库中有三个类可以用于文件操作,它们统称为文件流,这三个类是:
ifstream:用于文件中读取数据
ofstream:用于向文件中写入数据
fstream:既可用于从文件中读取数据,也可以向文件中写入数据。
使用这三个类时,程序中需要包含fstream头文件。C++类库中的流类如下图所示。
ifstream类和fstream类是从istream类派生出来的,因此ifstream类拥有istream类的全部成员函数。同样地,ofstream和fstream类也拥有ostream类的全部成员函数。这三类中有一些十分熟悉的成员函数可以使用,如operator<<、operator>>、peek、ignore、getline、get等。
在程序中,要使用一个文件,先要打开文件后才能读写,读写完后要关闭。创建一个新文件也要先打开,然后才能往文件按中写入数据。C++文件流类有相应的成员函数来实现打开、读、写、关闭等文件操作。
C++打开文件
在对文件进行读写操作之前,先要打开文件。打开文件有两个目的:
(1)通过指定文件名,建立起文件和文件流对象的关联,以后要对文件进行操作时,就可以通过与之关联的流对象来进行。
(2)指明文件的使用方式,使用方式有只读、只写、读写,在文件末尾添加数据、以文本方式使用、以二进制方式使用等多种方式。
打开文件的两种方式:
(1)调用流对象的open成员函数打开文件。
(2)定义文件流对象时,通过构造函数打开文件。
关闭文件时,调用文件流的close成员函数即可。
使用open函数打开文件
以ifstream类为例,该类有一个open成员函数,其他两个文件流也有同样的Open成员函数;
void open(const char* szFileName,int mode)
第一个参数是指向文件名的指针,第二个参数是文件的打开模式标记。
文件的打开模式标记代表了文件的使用方式,这些标记可以单独使用,也可以组合使用。表1列出了各种模式标记单独使用时的作用,以及常见的两种模式标记组合的作用。
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("c\\tmp\\test.txt",ios::in);
if(inFile)//条件成立,则说明摁键打开成功
inFile.close();
else
cout<<"test.txt doesn't exist"<<endl;
ofstream oFile;
oFile.open("tset1.txt",ios::out);
if(!oFile)
cout<<"error 1"<<endl;
else
oFile.close();
oFile.open("tmp\\test2.txt",ios::out|ios::in);
if(oFile)
oFile.close();
else
cout<<"error 2"<<endl;
fstream ioFile;
ioFile.open("..\\test3.txt",ios::out|ios::in|ios::trunc);
if(!ioFile)
cout<<"error 3"<<endl;
else
ioFile.close();
return 0;
}
调用open成员函数时,给出的文件名可以是全路径的,如c:\\tmp\\test.txt,指明文件在c盘的tmp文件夹中;也可以只给出文件名,如test1.txt,这种情况下程序会在当前文件夹(即可执行程序所在的文件夹)中寻找要打开的文件。tmp\\test2.txt给出的是相对路径,说明test2.txt位于当前文件夹的tmp子文件夹中。
使用流类的构造函数打开文件
定义流对象时,在构造函数中给出文件名和打开模式也可以打开文件。以ifstream类为例,它有如下构造函数:
ifstream::ifstream (const char* szFileName, int mode = ios::in, int);
第一个参数是指向文件名的指针;第二个参数是打开文件的模式标记,默认为ios::in;第三个参数是整型的,也有默认值,一般极少使用。
使用流类的构造函数打开文件的例子:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream inFile("c:\\tmp\\test.txt", ios::in);
if (inFile)
inFile.close();
else
cout << "test.txt doesn't exist" << endl;
ofstream oFile("test1.txt", ios::out);
if (!oFile)
cout << "error 1";
else
oFile.close();
fstream oFile2("tmp\\test2.txt", ios::out | ios::in);
if (!oFile2)
cout << "error 2";
else
oFile.close();
return 0;
}