文件操作

本章内容为coursera课程C++程序设计中第七周的课件的整理

数据的层次

位 bit
字节 byte
域/记录:
将所有记录顺序地写入一个文件叫做顺序文件
例如: 学生记录
int ID;
char name[10];
int age;

int rank[10];


文件和流
顺序文件 — 一个有限字符构成的顺序字符流
C++标准库中: ifstream, ofstreamfstream共3个类,用于文件操作,统称为文件流类


网上找的图:


#include <fstream>  
ofstream         //文件写操作 内存写入存储设备   
ifstream         //文件读操作,存储设备读区到内存中  
fstream          //读写操作,对打开的文件可进行读写操作 

文件操作
使用/创建文件的基本流程



1.打开文件


(上图方式属于默认方式打开,当使用默认方式进行对文件的操作时,你可以使用成员函数is_open()对文件是否打开进行验证)

也可以先创建 ofstream对象, 再用 open函数 打开

ofstream fout;
fout.open( “test.out”, ios::out|ios::binary );

打开文件的方式在ios类(所有流式I/O的基类)中定义,有如下几种方式:

ios::in为输入(读)而打开文件
ios::out为输出(写)而打开文件
ios::ate初始位置:文件尾
ios::app所有输出附加在文件末尾
ios::trunc如果文件已存在则先删除该文件
ios::binary二进制方式
这些方式是能够进行组合使用的,以“或”运算(“|”)的方式

判断打开是否成功:
if(!fout) { cerr << “File open error!”<<endl; }
文件名可以给出绝对路径, 也可以给相对路径
没有交代路径信息, 就是在当前文件夹下找文件.


2.文件的读写

读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;

而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式

2.1 文本文件的读写  

(这部分没讲,待看)

文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。

假设file1是以输入方式打开,file2以输出打开。示例如下:

file2<<"I Love You";//向文件写入字符串"I Love You"   
int i;   
file1>>i;//从文件输入一个整数值。  


文件的读写指针
对于输入文件,有一个读指针;对于输出文件, 有一个写指针;对于输入输出文件, 有一个读写指针。
标识文件操作的当前位置,该指针在哪里,读写操作就在哪里进行。

文件的写指针

ofstream fout(“a1.out”, ios::app);
long location = fout.tellp(); //取得写指针的位置
location = 10L;
fout.seekp(location); // 将写指针移动到第10个字节处
fout.seekp(location, ios::beg); //从头数location
fout.seekp(location, ios::cur); //从当前位置数location
fout.seekp(location, ios::end); //从尾部数location
location 可以为负值,负值就从末尾开始读
文件的读指针
ifstream fin(“a1.in”,ios::in);
long location = fin.tellg(); //取得读指针的位置
location = 10L;
fin.seekg(location); //将读指针移动到第10个字节处
fin.seekg(location, ios::beg); //从头数location
fin.seekg(location, ios::cur); //从当前位置数location
fin.seekg(location, ios::end); //从尾部数location
location 可以为负


2.2二进制文件读写

①put()  

put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。

②get()  

get()函数比较灵活,有3种常用的重载形式:

一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。

另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。

还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:

file2.get(str1,127,'A');     //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。   

③读写数据块

要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:

read(unsigned char *buf,int num);   
write(const unsigned char *buf,int num);  
read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。例:
unsigned char str1[]="I Love You";       
int n[5];       
ifstream in("xxx.xxx");       
ofstream out("yyy.yyy");       
out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中       
in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换       
in.close();out.close();   

文件流包括两个为顺序读写数据特殊设计的成员函数:write read。第一个函数 (write) 是ostream 的一个成员函数,都是被ofstream所继承。而read 是istream 的一个成员函数,被ifstream 所继承。类 fstream 的对象同时拥有这两个函数。它们的原型是:

write ( char * buffer, streamsize size );
read ( char * buffer, streamsize size );

这里 buffer 是一块内存的地址,用来存储或读出数据。参数size 是一个整数值,表示要从缓存(buffer)中读出或写入的字符数。

int x=10;
fout.seekp(20, ios::beg);
fout.write( (const char *)(&x), sizeof(int) );
fin.seekg(0, ios::beg);
fin.read( (char *)(&x), sizeof(int) );
二进制文件读写, 直接写二进制数据, 记事本看未必正确


//例1.下面的程序从键盘输入几个学生的姓名的成绩,并以二进制, 文件形式存起来
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
class CStudent {
public:
char szName[20];
int nScore;
};

int main()
{
CStudent s;
ofstream OutFile( “c:\\tmp\\students.dat”, ios::out|ios::binary );
while( cin >> s.szName >> s.nScore ) {
if( stricmp(s.szName, “exit” ) == 0) //名字为exit则结束
break;
OutFile.write( (char *) & s, sizeof(s) );
}
OutFile.close();
return 0;
}
输入:
Tom 60
Jack 80
Jane 40

exit 0

//例2.下面的程序将 students.dat 文件的内容读出并显示
#include <iostream>
#include <fstream>
using namespace std;
class CStudent
{
public:
char szName[20];
int nScore;
};
int main(){
CStudent s;
ifstream inFile("students.dat", ios::in | ios::binary );
if(!inFile) {
cout << "error" <<endl;
return 0;
}
while( inFile.read( (char* ) & s, sizeof(s) ) ) 
{
int nReadedBytes = inFile.gcount(); //看刚才读了多少字节
cout << s.szName << " " << s.score << endl;
}
inFile.close();
return 0;
}
输出:
Tom 60
Jack 80
Jane 40


//例3.下面的程序将 students.dat 文件的Jane的名字改成Mike
#include <iostream>
#include <fstream>
using namespace std;
class CStudent
{
public:
char szName[20];
int nScore;
};
int main(){
CStudent s;
fstream iofile( “c:\\tmp\\students.dat”, ios::in|ios::out|ios::binary);
if(!iofile) {
cout << "error" ;
return 0;
}
iofile.seekp( 2 * sizeof(s), ios::beg); //定位写指针到第三个记录
iofile.write( “Mike”, strlen("Mike")+1);
iofile.seekg(0, ios::beg); //定位读指针到开头
while( iofile.read( (char* ) & s, sizeof(s)) )
cout << s.szName << " " << s.nScore << endl;
iofile.close();
return 0;
}
输出:
Tom 60
Jack 80
Mike 40

//例4: mycopy 程序, 文件拷贝
//用法示例:
//mycopy src.dat dest.dat
//即将 src.dat 拷贝到 dest.dat
//如果 dest.dat 原来就有, 则原来的文件会被覆盖
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, char * argv[]){
if(argc != 3) {
cout << "File name missing!" << endl;
return 0;
}
ifstream inFile(argv[1], ios::binary|ios::in); //打开文件用于读
if(! inFile) {
cout << “Source file open error.” << endl;
return 0;
}
ofstream outFile(argv[2], ios::binary|ios::out); //打开文件用于写
if(!outFile) {
cout << “New file open error.” << endl;
inFile.close(); //打开的文件一定要关闭
return 0;
}
char c;
while(inFile.get(c)) //每次读取一个字符   //
outFile.put(c); //每次写入一个字符        //
outFile.close();
inFile.close();
return 0;
} 

3.显式关闭文件

当文件读写操作完成之后,我们必须将文件关闭以使文件重新变为可访问的。成员函数close(),它负责将缓存中的数据排放出来并关闭文件。这个函数一旦被调用,原先的流对象就可以被用来打开其它的文件了,这个文件也就可以重新被其它的进程所访问了。为防止流对象被销毁时还联系着打开的文件,析构函数将会自动调用关闭函数close。

ifstream fin(“test.dat”, ios::in);
fin.close();
ofstream fout(“test.dat”, ios::out);
fout.close();




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值