文件操作和文件流

文件流是以外存文件为输入输出对象的数据流。每一个文件流都有一个内存缓冲区与之对应。要以磁盘文件为对象进行输入输出,必须定义一个文件流类的对象,它使数据从内存输出到磁盘文件,或者通过文件流对象将数据从磁盘文件输入到内存。

在C++的 I/O 类库中定义了三种流可以处理文件操作:

  • ifstream类,是从输入流 istream 类派生的,支持从磁盘文件的输入操作。
  • ofstream类,是从输出流 ostream 类派生的,支持向磁盘文件的输出操作。
  • fstream类,是从输入输出流 iostream 类派生的,支持对磁盘文件的输入输出操作。

流对象的定义:

ifstream fInput;
ofstream fOutput;
fstream  sIO;

打开文件

  • 使用 open() 函数
ifstream fTemps;
fTemps.open("Temp.dat");
  • 定义对象时指定参数(常使用这种方式打开文件,简单便捷
ifstream fGrade("Grade.dat",ios::out);    //以输出的方式打开文件Grade.dat

设置文件打开方式

为了对文件操作的方便,我们需要采用不同的打开方式对文件进行操作。同时我们还可以使用或 ‘|’ 对打开方式进行组合。

文件流的输入输出方式
标识常量 意义
ios::in(输入默认) 读(输入)方式打开文件
ios::out(输出默认1) 写(输出)方式打开文件
ios::ate 打开文件时,指针指向文件尾
ios::app 追加方式
ios::trunc(输出默认2) 删除文件现有内容
ios::nocreate 如果文件不存在,则打开操作失败
ios::noreplace 如果文件存在,则打开操作失败
ios::binary 二进制方式打开,默认为文本方式

同样,打开方式可以在 open() 函数中设置,也可以在流对象中设置。

ifstream infile;                            //建立输出文件流对象
infile.open("datafile.dat",ios::in);        //连接文件,指定以输入方式打开文件

ofstream outfile;                           //建立输出文件流对象
outfile.open("newfile.dat",ios::out);       //连接文件,指定以输出方式打开文件

ifstream infile("datafile.dat",ios::in);

ofstream outfile("newfile.dat",ios::out); 

fstream rwfile("myfile.dat",ios::in | ios::out); //连接文件,指定读写方式

关闭文件

文件关闭操作先把缓冲区中的数据完整的写入文件,而后添加文件结束标志,最终切断流对象和外部文件的连接。文件可以调用 close() 函数来关闭

ofstream ofile;            //创建输出文件流
ofile.open("myfile1");     //流与文件关联
ofile.close();             //关闭文件

打开与关闭错误

  • 可以使用取反操作符测试文件是否成功打开:
if(!outfile)
{
    cout<<"error:unable to open myfile!";
    return 1;
}
  • 如果关闭未打开的文件,会造成操作失败。为了测试是否成功关闭文件,可以调用 fail() 函数判断:
outfile.close();
if(outfile.fail())
    cerr<<"error to close myfiles!";

文本文件的读写

如果文件的每一个字节均以ASCII 代码形式存放数据,即一个字节存放一个字符,这个文件就是ASCII文件,也称文本文件或称字符文件。此类文件用默认打开方式,程序可以从文本文件中读入若干个字符,也可以向他输入一些字符。对这些文本文件进行读写操作,可以使用流运算符 << 和 >> ,也可以调用文件流的 put(),get(),getline() 等成员函数

(1)将数据输出到文件例程如下,实际是使用 outFile 代替 cout 即可。

// primeNumberstoFile.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <fstream>
#include <iomanip>

int _tmain(int argc, _TCHAR* argv[])
{
	const int max = 25;
	long primes[max] = {2,3,5};				//素数数组,前3个元素为2,3,5
	int count = 3;							//记录素数的个数
	long trial = 5;							//被筛选数
	bool isprime = true;					//判断素数的bool值

	do
	{
		trial += 2;							//更新被筛选数
		int i = 0;							//素数数组下标

		//判别素数
		do
		{
			isprime = trial % *(primes + i) > 0;
		} while(++i < count && isprime);

		if(isprime )
			*(primes + count++) = trial;	//将筛选的素数存储到数组中
	}while(count<max);

	std::ofstream outFile("D:\\ApplicationWorkSpace\\C++\\testStreamState\\primes.txt");	//定义输出流对象,与文件相连

	//将所有素数格式化的写入文件
	for( int i = 0; i < max; i++ )
	{
		if(i%5 == 0)
			outFile<<std::endl;
		outFile<<std::setw(10)<<*(primes + i);	//将数组中的数据逐个写入文件
	}

	return 0;
}

(2)读取文件在屏幕中显示:

// filetoPrimeNumbers.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <iomanip>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	const char* filename = "D:\\ApplicationWorkSpace\\C++\\testStreamState\\primes.txt";	//文件名及路径
	ifstream inFile(filename);				//创建流对象

	//流状态检测
	if(!inFile)
	{
		cout<<endl<<"Failed to open file "<<filename;
		return 1;
	}

	long aprime = 0;
	int count = 0;							//记录素数的个数
	while(!inFile.eof())					//读取数据直到EOF
	{
		inFile>>aprime;						//从文件中读取数据
		cout<<(count++ % 5 == 0 ? "\n" : "")//将数据格式化输出到屏幕
			<<setw(10)<<aprime;
	}
	cout<<endl;

	return 0;
}

结果


         2         3         5         7        11
        13        17        19        23        29
        31        37        41        43        47
        53        59        61        67        71
        73        79        83        89        97
请按任意键继续. . .

二进制文件操作

二进制文件将内存中数据不加转换的传送到磁盘文件,并且将数据按二进制的格式存储在各个字节中,因此它又称为内存数据的映像文件或字节文件

对二进制文件在打开时要用ios::binary指定为以二进制形式传送和存储。对于文件的操作可以使用流类的成员函数 read() 和 write() ,高效便利地读写成批地数据。

(1)读文件函数

原型:istream& read(char *buffer, int len);

使用:

ifstream input("area.dat",ios::binary|ios::in);    //打开文件
int iAry[3];                                       //建立缓冲区
input.read((char*)iAry, 3*sizeof(int));

//read函数常用来读取文件中结构化的记录,对应缓冲区的长度由该结构存储的各种类型的数据决定。


//使用函数成块的传输一个记录,对于不同类型的数据不必进行格式化。
bool readStudent(Stu& oneStudent, ifstream& fStudent)
{
    fStudent.read((char*)&oneStudent, sizeof(Stu));
    bool ioFlag = fStudent.good();
    return ioFlag;
}

(2)写文件函数

原型:ostream& write(const char * buffer, int len);

使用:

Oput.write((char*)iAry, 3*sizeof(int));    //调用方式

//定义写入结构记录的函数
void write(Stu& aStudent, ofstream& fsStuOut)
{
    fsStuOut.write((char*)aStudent, sizeof(Stu));    //将一条记录写入文件
    if(!fsStuOut.good())
    {
        cerr<<"\a Error in writing student file."<<endl;
        exit(100);
    }
    return;
}

(3)文件定位函数

二进制文件的读写方式由程序控制,这种类型的文件不是顺序存储的,可以根据文件指针随机读写数据。为了确定文件指针的位 置(指定为long int类型),ios类中定义的设定枚举常量作为参照位置:enum ios::seek_dir{beg = 0, cur = 1, end = 2 }; 文件的开头用 ios::beg 表示,这是文件指针的默认值。指针当前位置用 ios::cur 表示。文件末尾用 ios::end 表示。

文件流中提供了一些有关文件指针的成员函数,使它按用户的意图移动到指定的位置,以便再该位置上进行读写。

  • tellp()与tellg():获取指针位置。函数返回当前指针相对于文件起点的偏移量。文本文件中,可以使用tell函数查找文件中数据的位置。tell函数返回0,表明文件指针位于 ios::beg。指针位于第二字节处,则返回1,表明存在一个偏移量。
istream & istream::tellg();    //用于输入文件,返回读指针当所指位置值
ostream & ostream::tellp();    //用于输出文件,返回读指针当所指位置值
  • seekp()与seekg():设置指针位置。用于对磁盘文件的定位操作,它们可以设定当前指针在文件中的字节位置,实现定位的功能。seekg()用于定位输入文件的位置,seekp()用于定位输出文件的位置。声明和调用如下:
istream & istream::seekg(long pos);          //读指针从流的起始位置向后移动pos个字节
istream & istream::seekg(long off, ios::seek_dir where);
//读指针从流的where位置移动off个字节

ostream & ostream::seekp(long pos);          //写指针从流的起始位置向后移动pos个字节
ostream & ostream::seekp(long off, ios::seek_dir where);
//写指针从流的where位置移动off个字节


//调用形式
fsInput.seekg(256L,ios::beg);            //等效于fsInput.seekh(256L);
fsOutput.seekp(sizeof(Stu),uos::cur);    //指针从当前位置向后移动一条Stu记录的字节数
File.seekp(-40, ios::end);               //文件指针从文件尾向前移动40个字节

例子:文件的读写

// fileReadWrite.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <fstream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	fstream f("D:\\ApplicationWorkSpace\\C++\\testStreamState\\DATA.dat",ios::in|ios::out|ios::binary);
	//定义一个可输入输出的二进制文件对象
	int i;

	for( i = 0; i < 20; i++ )	//先写入20个整数
		f.write((char*)&i,sizeof(int));
	long pos = f.tellp();		//记录当前指针所在位置值
	for( i = 20; i < 40; i++ )	//再写入20个整数
		f.write((char*)&i,sizeof(int));

	f.seekg(pos);				//将指针移到pos所表示的位置
	f.read((char*)&i,sizeof(int));	//读入一个数据
	cout<<"The data stored is "<<i<<endl;

	f.seekp(0,ios::beg);		//指针移到文件开始
	for( i = 0; i < 40; i++ )	//显示全部数据
	{
		f.read((char*)&i,sizeof(int));
		cout<<i<<ends;			//ends结束时加一个空格
	}
	cout<<endl;

	return 0;
}

输出结果
The data stored is 40
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
请按任意键继续. . .

字符串流

字符串流:istringstream、ostringstream、stringstream,串流类是ios的派生类。

构造函数原型:

ostringstream::ostringstream(char *buffer, int n, int mode=ios::out);//建立输出字符串流对象
istringstream::istringstream(char *buffer, int n);                   //建立输入字符串流对象
stringstream::stringstream(char *buffer, int n, int mode);           //建立输入输出字符串流对象

采用此方法在建立流对象时,通过给定参数来确定字符串流与特定字符数组的连接。

char buf[80];
ostrstream Output( buf, sizeof(buf) );

由于该字符数组没有相应的结束标志,用户要指定特殊字符作为结束符号。

Output<<x<<"*"<<y<<"="<<x*y<<ends;    //插入ends等效于在流中加入'\0'

字符串操作的例子1

// stringReadWrite.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <sstream>
#include <string>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	string testStr("Input test 256 * 0.5");
	string s1,s2,s3;
	double x,y;

	istringstream input( testStr );			//串流对象与string对象关联
	//将字符转换为二进制格式赋给相应变量或对象
	input>>s1>>s2>>x>>s3>>y;
	cout<<s1<<ends<<s2<<ends
		<<x<<s3<<y<<"="<<x*y<<endl;
	return 0;
}

结果
Input test 256*0.5=128
请按任意键继续. . .

字符串操作的例子2

#include "stdafx.h"
#include <iostream>
#include <sstream>
#include <string>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	ostringstream Output;
	double x,y;
	cout<<"Input x and y:";
	cin >> x >> y;
	//将数据写入流中
	Output<<x<<"*"<<y<<"="<<x*y<<endl;				
	cout<<Output.str();								//显示字符串
	return 0;
}

结果
Input x and y:3 4.5
3*4.5=13.5
请按任意键继续. . .
发布了50 篇原创文章 · 获赞 21 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/u012839256/article/details/104732170