C++文件操作


在这里插入图片描述

1.文件的打开和关闭

  • 打开文件可以通过以下两种方式进行:
    1)调用流对象的 open 成员函数打开文件。
    2)定义文件流对象时,通过构造函数打开文件
void open(const char* szFileName, int mode)
  • 文件的打开模式标记代表了文件的使用方式,这些标记可以单独使用,也可以组合使用。如下列出了各种模式标记单独使用时的作用,以及常见的两种模式标记组合的作用。
    在这里插入图片描述
  • ios::binary 可以和其他模式标记组合使用,例如:

ios::in | ios::binary表示用二进制模式,以读取的方式打开文件。
ios::out | ios::binary表示用二进制模式,以写入的方式打开文件。

//打开文件
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
    ifstream inFile;          //流类ifstream 建立读取数据的文件流对象
    inFile.open("c:\\tmp\\test.txt", ios::in);   //调用流对象的 open 成员函数打开准备读取的
//文件。参数是文件名和打开模式 
//    \\表示一个\                  
    if (inFile)  //判断流对象名的表达式,若果为真true,条件成立,则说明文件打开成功
        inFile.close();   //关闭文件时,调用文件流对象的 close 成员函数即可。 
    else
        cout << "test.txt doesn't exist" << endl;
    ofstream oFile;       //流类ofstream  建立写入数据的文件流对象
    oFile.open("test1.txt", ios::out);      //调用流对象的 open 成员函数打开准备写入数据的文
//件。参数是文件名和打开模式                   
    if (!oFile)  //判断流对象名的表达式,条件成立(PS:注意此处是!非),则说明文件打开出错
        cout << "error 1" << endl;
    else
        oFile.close();  //关闭文件时,调用文件流对象的 close 成员函数即可。
    oFile.open("tmp\\test2.txt", ios::out | ios::in);  //第二个参数打开模式是  打开已存在的
//文件,既可读取其内容,也可向其写入数据。文件刚打开时,原有内容保持不变。如果文件不存在,则打开
//出错。
    if (oFile)  //条件成立,则说明文件打开成功
        oFile.close();
    else
        cout << "error 2" << endl;
    fstream ioFile;    //流类fstream
    ioFile.open("..\\test3.txt", ios::out | ios::in | ios::trunc);//第二参数打开模式是打
//开文件,既可读取其内容,也可向其写入数据。如果文件本来就存在,则打开时清除原来的内容;如果文件
//不存在,则新建该文件。
    if (!ioFile)
        cout << "error 3" << endl;
    else
        ioFile.close();
    return 0;
}
  • 定义流对象时也可以打开文件
ifstream::ifstream (const char* szFileName, int mode = ios::in, int);
  • 代码实例
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
    ifstream inFile("c:\\tmp\\test.txt", ios::in);  //流ifstream 直接使用定义流对象打开要读取数据的文
//件,不要流对象的类下的open()成员函数
    if (inFile)
        inFile.close();
    else
        cout << "test.txt doesn't exist" << endl;
    ofstream oFile("test1.txt", ios::out); //流ofstream 直接使用定义流对象打开要写入数据的文件,不要流对
//象的类下的open()成员函数
    if (!oFile)
        cout << "error 1";
    else
        oFile.close();
    fstream oFile2("tmp\\test2.txt", ios::out | ios::in);   //流fstream同上 此文件即可写入也可读取
    if (!oFile2)
        cout << "error 2";
    else
        oFile.close();
    return 0;
}

1.2文件名路径说明

  • 1)全路径
c:\\tmp\\test.txt  //指明文件在 c 盘的 tmp 文件夹中
  • 2)只给出文件名
test1.txt  //这种情况下程序会在当前文件夹(也就是可执行程序所在的文件夹)中寻找要打开的文件
  • 3)相对路径
tmp\\test2.txt  //给出的是相对路径,说明 test2.txt 位于当前文件夹的 tmp 子文件夹中
  • 4)上一层路径
..\\test3.txt   //也是相对路径,代表上一层文件夹,此时要到当前文件夹的上一层文件夹中查找 test3.txt

…\\…\\test4.txt、…\\tmp\\test4.txt等都是合法的带相对路径的文件名。

2.文件的读写

2.2 文本文件的读写

例题:编写一个程序,将文件in.txt中的整数排序后输出到out.txt。例如,若in.txt的内容为:
1 234 9 45
6 879
则执行本程序后,生成的out.txt的内容为:
1 6 9 45 234 879

#include <iostream>
#include <vector>
#include<algorithm>
#include<stdlib.h>
#include<cstdlib>
#include<fstream>

using namespace std;

const int MAX_NUM = 1000;
int a[MAX_NUM];
int MyCompare(const void*el,const void* e2)
{
    return *((int*)el) - *((int*)e2);
}
int main()
{
    //1
    int total = 0;                      //读入的整数个数
    ifstream srcFile("in.txt",ios::in); //以文本反射光hi打开in.txt以备读取
    if(!srcFile)                        //打开失败
    {
        cout<<"error opening source file."<<endl;
        return 0;
    }


    //2
    ofstream destFile("out.txt",ios::out);//以文本方式打开以备写入
    if(!destFile)
    {
        srcFile.close();    //程序结束前,不要忘记关闭以前打开过的文件
        cout<<"error opening destination file."<<endl;
        return 0;
    }

    //3
    int x;
    while(srcFile>>x)   //可以像使用cin那样用ifstream对象接收输入
    {
        a[total++] = x;//内容放到数组
    }
    qsort(a,total,sizeof(int),MyCompare);//排序
    for(int i = 0;i<total;++i)
    {
        destFile<<a[i]<<" ";
    }

    //4
    destFile.close();
    srcFile.close();
    return 0;
}


打印效果:
在这里插入图片描述

2.3 二进制文件的读写

  • 用文本方式存储信息不但浪费空间,而且不利于检索。
  • 可以用二进制的方式存储学生对象,对象写入文件一般称作"记录",每个学生对应一条记录,用折半查找的效率会很高
  • 读取二年简直方法可以调用ifstream对象和fstream对象的read成员函数从文件中读取数据,调用ofstream和fstream的write成员函数向文件中写入数据
1)write成员函数写文件
ostream& write(char* buffer,int count);//将buffer中的count个字节写入文件,返回值是对函数锁作用对象的引用,如obj。write的返回值就是对obj的引用
  • write函数在执行的函数把若干字节写到文件写指针指向的位置
2)read成员函数读文件
ostream& read(char* buffer,int count);//从文件都指针指向的文职开始读取若干字节,文件都种子很时ifstream或fstream对象内部维护的一个变量。文件刚打开时,文件读指针指向文件的开头
  • 文件都指针若以ios::ate方式打开,则指向文件末尾,read后,读指针指向的位置就向后移动n个字节
  • 下面的程序从键盘输入几名学生的姓名和年龄(输入时,在单独的一行中按照Ctrl+Z键再按回车以结束符终止。假设学生名字中都没有空格)
    代码:
#include <iostream>
#include <vector>
#include<algorithm>
#include<stdlib.h>
#include<cstdlib>
#include<fstream>

using namespace std;

class CStudent
{
public:
    char szName[20];
    int age;
};

int main()
{
    //1.写进文件
    CStudent s;
    // ofstream outFile("Students.dat",ios::out | ios::binary);//二进制写模式打开
    // int i = 0;
    // while(cin>>s.szName>>s.age)
    // {   
        // if(3==i)
            // break;
        // i++;
        // outFile.write((char*)&s,sizeof(s));
    // }

    //2.读出来
    ifstream inFile("Students.dat",ios::in|ios::binary);//二进制读方式打开
    if(!inFile)
    {
        cout<<"inFile error"<<endl;
        return 0;
    }

    while(inFile.read((char*)&s,sizeof(s))) //读到文件结束
    {
        int readedBytes = inFile.gcount();  //记录读了多少字节
        cout<<s.szName<<" "<<s.age<<endl;
    }

    inFile.close();
    //outFile.close();

    return 0;
}

效果:
在这里插入图片描述

在这里插入图片描述

3)利用文件流类的put和get成员函数读写文件
  • 可以用ifstream和fstream类的get成员函数从文件中读取一个字节,也可以用ofstream和fstream类的put函数(继承自ostream类)向文件中一次写入一个字节
    例题:编写一个mycopy程序,实现文件复制的功能。用法时再命令提示符窗口输入:
    mycopy 源文件名 目标文件名
    就能将源文件复制到目标文件。例如:
    mycopy src.dat dest.dat
    即将src.dat复制到dest.dat。如果dest.dat原本就存在,则原来的文件会被覆盖.
  • 代码:
#include <iostream>
#include <vector>
#include<algorithm>
#include<stdlib.h>
#include<cstdlib>
#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;
}


2.4 操作文件读写指针

  • ifstream类和fstream类有seekg成员函数,可以设置文件都指针的位置
  • ofstream类和fstream类有seekp成员函数,可以设置文件写指针的位置
  • 位置:举例文件开头有多少字节,开头位置为0
ofstream &seekp(int offset,int mode);
istream &seekg(int offset,int mode);
  • mode代表文件读写指针的设置模式,有以下三种选择:

ios::beg:让文件读指针(或写指针)指向从文件开始后的offset字节处。offset等于0即代表文件开头,在此情况下,offset只能是非负数
ios::cur:在此情况下,offset为负数则表示将读指针(或写指针)从当前位置朝文件开头方向移动offset字节,为0表示不动
ios::end:让文件读指针(或指针)指向从我呢见结尾往前的|offset|(offset的绝对值)字节处。在此情况下,offset只能是0或者非负数

  • ifstream类和fstream类还有tellg成员函数,能够返回文件读指针的位置
int tellg();
  • ofstream类和fstream类还有tellp成员函数,能够返回文件写指针的位置
int tellp();
  • 用处:获取文件长度

用seekg函数将文件读指针定位到文件尾部,再用tellg函数获取文件读指针的位置,此位置为文件长度

  • 例题:假设学生记录文件students.dat是按照姓名排好序的,编写程序,在students.dat文件中用折半查找的方法找到姓名为Jack的学生记录,并将年龄改为20(假设文件很大,无法全部读入内存),程序如下:
#include <iostream>
#include <vector>
#include<algorithm>
#include<stdlib.h>
#include<cstdlib>
#include<fstream>
#include <string.h>
//#include <memcopy.h>

using namespace std;

class CStudent
{
public:
    char szName[20];
    int age;
};

int main()
{
    //1.打开文件
    CStudent s;
    fstream ioFile("Students.dat",ios::in|ios::out);//用即读又写的方式打开文件
    if(!ioFile)                                     //若打开失败
    {
        cout<<"error";
        return 0;
    }

    //2获取文件总长度
    ioFile.seekg(0,ios::end);//定位都指针到文件尾部,以便用tellg函数获取文件长度
    int L = 0,R;//L是折半查找范围内第一个记录的序号,R是折半查找范围内最后一个记录的序号
    R = ioFile.tellg()/sizeof(CStudent)-1;//首次查找范围的最后一个记录的序号是:记录总数-1
                                          //R是文件总长度
    
    //3.二分查找
    do{
        int mid = (L+R)/2;//用查找范围正中间的记录和待查找的名字对比
        ioFile.seekg(mid*sizeof(CStudent),ios::beg);//定位到正中间的记录,ios::beg表示读指针指向从文件开始后的mid*sizeof(CStudent)个字节
        ioFile.read((char*)&s,sizeof(s));           
        int tmp = strcmp(s.szName,"JACK");          //若str1=str2,则返回零;若str1<str2,则返回负数;若str1>str2,则返回正数
        if(0==tmp)                                  //找到JACK了
        {
            s.age = 20;
            ioFile.seekp(mid*sizeof(CStudent),ios::beg);
            ioFile.write((char*)&s,sizeof(s));
            break;
        }
        else if(0 < tmp)    //继续到前一半查找
            R = mid -1;
        else                //继续到后一半查找
            L = mid+1;

    }while(L<=R);

    ioFile.close();
    return 0;
}


效果:
在这里插入图片描述

3 文本方式打开与二进制方式打开文件的区别

1)Linux

  • Linux/UNIX平台中,文本文件以’\n’(ASCII码为0x0a)作为换行符号

2)Windows

  • Windows平台中,文本文件以连在一起的"\r\n"(’\r’的ASCII码是0x0d)作为换行符号
  • 打开文件时,系统会把文件中所有的"\r\n"转换成一个字符’\n’。即当读入0x0d0a时,系统会丢失前面的0x0d这个字节,只读入0x0a。当写入文件时,系统会将’\n’转换成”\r\n“写入。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值