wangqiuji

 

C++之文件读写

一、C++ I/O流

头文件:fstream

C++把对文件的读写操作都封装在以下的类中:

类名 功能 继承 相当于
ofstream 对文件的写操作,默认以只写方式O_WRONLY|O_CREAT|O_TRUNC打开文件,文件不存在则创建、存在则清空 ostream类 "w"
ifstream ifstream类 对文件的读操作,默认以只读方式O_RDONLY打开文件,文件不存在则失败 istream类 "r"
fstream 对文件读写操作,默认以读写方式O_RDWR打开文件,文件不存在则失败,文件存在不清空 ofstream类、ifstream类 "r+"

二、C++对文本文件的读写

  1. 创建流对象,通过流对象打开文件

    ofstream ofs(const char *filename, openmode mode );
    

    ②通过成员函数方式,打开文件

    void open( const char *filename );
    void open( const char *filename, openmode mode );
        filename:文件的路径
        mode: 打开方式
            ios::app 添加输出 
            ios::ate 当已打开时寻找到EOF 
            ios::binary 以二进制模式打开文件 
            ios::in 为读取打开文件 
            ios::out 为写入打开文件 
            ios::trunc 覆盖存在的文件
    

    注意:ios::里面打开模式单独使用和混合使用时候有些功能会有所删减变化,不是简单的功能相加,具体底层调用哪个打开模式可以通过 strace ./a.out 来追踪底层对系统函数的调用

  2. 如何判断文件是否打开成功

    1. 通过 !流对象名 执行了该类的!运算符重载版本

      if(!ifs)    //  为真 失败
      
    2. 通过good\fail成员函数判断是否成功

      bool good();
      功能:判断上一次流操作是否成功,成功返回真,一般用于判断文件是否打开成功
      
  3. 读写文件
    ①流对象 << 写操作
    ②流对象 >> 读操作

  4. 关闭文件
    成员函数:

    void close(void)
    

    注意:只是关闭流对象当前的文件,但是流对象没有销毁,还可以继续通过open成员函数重新打开别的文件

  5. 如何以文本方式读写类对象?

    • 读写类对象时绝大部分成员变量都是私有的,因此无法直接在类外进行读写

    • 由于ostream/istream分别是ofstream/ifstream的父类,因此如果重载了>> <<运算符,既可以用于平时输出、输入类对象,并且还可以直接用于类对象的文本方式流操作读写

      cout << 类对象

      cin >> 类对象   重载后

      ofs << 类对象

      ifs >> 类对象   成立

三、C++的随机读写

C++为文件IO流提供了两套设置位置指针的成员函数,为了兼容一些有两个位置指针的操作系统,但是UNIX、Linux、Windows系统底层只有一个文件位置指针,所以使用哪套都没区别

istream &seekg( off_type offset, ios::seekdir origin );
    功能:通过 偏移量+基础位置 设置位置指针的位置
        offset:偏移量
        origin:基础位置
            ios::beg    文件开头
            ios::cur    当前位置
            ios::end    文件末尾
istream &seekg( pos_type position );
    功能:通过绝对值的方式设置位置指针的位置
    seekp 功能类似
pos_type tellp();
    功能:获取位置指针所在文件的绝对位置
    tellg功能类似

四、C++对二进制文本的读写

  1. 创建流对象、打开文件
    ios::binary    以二进制模式打开文件

  2. 读写操作

    ostream &write(const char *buffer,streamsize num);
        功能:以二进制方式写文件
        buffer:待写入数据的内存首地址
        num:待写入的字节数
    

    注意:C++的write只会有两种结果,要么num个字节全部写入,要么一个都没写入,可以通过good、fail判断上一次的写操作是否成功

    istream &read( char *buffer, streamsize num );
            功能:以二进制方式读文件
            buffer:存储读取到的数据的内存首地址
            num:要读取的字节数
    
    streamsize gcount();
            功能:获取上一次读操作中成功读取到的字节数
    
    bool eof();
            功能:判断读操作是否读到了文件末尾,如果是返回真
    
  3. 二进制读写需要注意的问题:

    • 对象的成员变量中不应该有指针类型(或string类型),因为此时写入时只会把指针变量存储的地址写入,而下次读取到该指针变量时,该指针地址已经没有意义了

    • 一直读取二进制文件

      while(true)
      {      
           //  读操作
           if(fs.eof()) break; 
           //  读成功,执行相应操作
      }
      
作业:使用C++实现一个mv带覆盖检查的命令
#include <iostream>
#include <unistd.h>
#include <fstream>
using namespace std;

int main(int argc,const char* argv[])
{
    if(3 != argc)
    {
        cout << "User: ./MV <src> <dest>" << endl;
        return -1;
    }

    ifstream ifs(argv[1]);
    if(!ifs)
    {
        cout << "原文件不存在,请检查!" << endl;
        return -1;
    }

    if(0 == access(argv[2],F_OK))
    {
        cout << "目标文件已存在,是否覆盖(y/n)?" << endl;
        char cmd;
        cin >> cmd;
        if('y' != cmd)
        {
            cout << "停止移动!" << endl;
            ifs.close();
            return 0;
        }
    }

    ofstream ofs(argv[2]);
    if(!ofs)
    {
        cout << "目标位置无权限,请检查!" << endl;
        ifs.close();
        return -1;
    }

    char buf[4096] = {};
    while(true)
    {
        ifs.read(buf,sizeof(buf));
        if(ifs.eof()) break;
        ofs.write(buf,ifs.gcount());
    }

    ifs.close();
    ofs.close();

    unlink(argv[1]);
}

posted on 2023-08-31 18:09  翻斗花园牛大爷!  阅读(53)  评论(0编辑  收藏  举报

导航