C++之fstream

一、ifstream

ifstream只能定义文件输入流对象:

#include<iostream>
#include<fstream>

using namespace std;

int main() {
    ifstream fs("abc.txt");
    if (!fs)
        cout << "open error" << endl;
    else
        cout << "open success" << endl;
    char ch;
    while (fs.get(ch), !fs.eof())
        cout << ch;
    cout << endl;
    system("pause");
    return 0;
}

由于fs是文件输入流对象,因此不能通过fs向文件abc.txt中写入文本,只能从abc.txt中读取文本,首先先手动在abc.txt中添加文本,在hello world最后有一个回车符。

这里写图片描述

输出结果:

这里写图片描述

注意:
1、当文件输入流对象fs打开一个不存在的文件时,会跳到open error的输出中,打开失败,也就是说文件输入流对象对不存在的文件并不会去生成这个文件,只有当文件存在时,才可以成功打开。

2、这里可以用过if(!fs)来判断文件是否成功打开,表示ifstream重载了运算符!。

二、ofstream

ofstream只能定义文件输出流对象:

#include<iostream>
#include<fstream>
#include<string.h>

using namespace std;

int main() {

    ifstream fsr("abc.txt");
    if (!fsr)
        cout << "open error" << endl;
    else
        cout << "open success" << endl;

    ofstream fsw("bca.txt");
    if (!fsw)
        cout << "open error" << endl;
    else
        cout << "open success" << endl;
    char ch;
    while (fsr.get(ch), !fsr.eof())
        fsw.put(ch);


    system("pause");
    return 0;
}

把fsr打开的文件中的文本读出来,然后写入到fsw打开的文本当中去:

这里写图片描述

这里写图片描述

注意:

1、对于文件输出流对象fsw可以成功打开一个不存在的文件,若打开一个已存在的文件则会把文件里面的内容清空。

2、这里可以用过if(!fsw)来判断文件是否成功打开,表示ofstream也重载了运算符!。

三、fstream

fstream可以定义输入/输出流对象。

1、运算符重载<< 和 >>

#include<iostream>
#include<fstream>
#include<string.h>

using namespace std;

int main() {

    fstream fsread("read.txt", ios::in | ios::out | ios::trunc);
    fstream fswrite;
    fswrite.open("write.txt", ios::in | ios::out | ios::trunc);

    fsread << "hello world" << endl;
    fsread << "i like c" << endl;
    fsread << "i lile c++" << endl;
    fsread << "i like game" << endl;
    fsread.seekg(0, ios::beg);
    char buf[1024];
    for (int i = 0; i < 4; i++) {
        fsread >> buf;
        cout << buf << endl;
        fswrite << buf;
        memset(buf, 0, sizeof(buf));
    }

    system("pause");
    return 0;
}

<1>

fstream fsread("read.txt", ios::in | ios::out | ios::trunc);
fstream fswrite;
fswrite.open("write.txt", ios::in | ios::out | ios::trunc);

fstream可通过构造函数打开文件,也可以通过成员函数open打开文件,这里列出打开的各种方式:

这里写图片描述

说明:
1) 在实际使用过程中,可以根据需要将以上打开文件的方式用“|”组合起来。如:
ios::in|ios::out 表示以读/写方式打开文件
ios::in|ios:: binary 表示以二进制读方式打开文件
ios::out|ios:: binary 表示以二进制写方式打开文件
ios::in|ios::out|ios::binary 表示以二进制读/写方式打开文件
2) 如果未指明以二进制方式打开文件,则默认是以文本方式打开文件。
3) 对于 ifstream 流, mode 参数的默认值为 ios::in,
对于 ofstream 流,mode 的默 认值为 ios::out|ios::trunc,
对于 fstream 流, mode 的默认值为 ios::int|ios::out|ios::app
4) 也可以通过,构造函数打开文件。
5) 出错处理是通过,对类对象进行判断的。若文件打开成功,返回 1,否则返回 0

<2>

fsread << "hello world" << endl;
fsread << "i like c" << endl;
fsread << "i lile c++" << endl;
fsread << "i like game" << endl;

通过运算符重载<<向fsread流对象中写入文本。

<3>

fsread.seekg(0, ios::beg);

将当前文件指针指回到文本开始处。
与文件指针相关的函数:

这里写图片描述

seek和tell最后的字母g表示get,p表示out,对于ifstream定义得输入流对象只能用tellg, seekg;ofstream定义的输出流对象只能用tellp, seekp函数,对于fstream定义的输入输出流对象都可以使用。

参照位置:

这里写图片描述

<4>

for (int i = 0; i < 4; i++) {
    fsread >> buf;
    cout << buf << endl;
    fswrite << buf;
    memset(buf, 0, sizeof(buf));
}

这里通过运算符重载的目的是将fsread流对象打开的文本内容复制到fswrite打开的文件中。

输出结果:

这里写图片描述

可以看到当fsread流到buf中去时,遇到空格就停止流入了,这是之前提到过的流对象重载运算符>>的缺陷,所以同样这里也是用成员函数来解决。

2、成员函数get

#include<iostream>
#include<fstream>
#include<string.h>

using namespace std;

int main() {
#if 0
    ifstream fsr("abc.txt");
    if (!fsr)
        cout << "open error" << endl;
    else
        cout << "open success" << endl;

    ofstream fsw("bca.txt");
    if (!fsw)
        cout << "open error" << endl;
    else
        cout << "open success" << endl;
    /*char buf[1024];
    memset(buf, 0, sizeof(buf));
    while (fs.getline(buf, 1024, '\n'), !fs.eof())
        cout << buf;*/
    char ch;
    while (fsr.get(ch), !fsr.eof())
        fsw.put(ch);

    fsw.open("bac.txt", ios::in | ios::out);
#endif

    fstream fsread("read.txt", ios::in | ios::out | ios::trunc);
    fstream fswrite;
    fswrite.open("write.txt", ios::in | ios::out | ios::trunc);

    fsread << "hello world" << endl;
    fsread << "i like c" << endl;
    fsread << "i lile c++" << endl;
    fsread << "i like game" << endl;
    fsread.seekg(0, ios::beg);
    //char buf[1024];
    char ch;
    while (fsread.get(ch), !fsread.eof())
        fswrite << ch;

    system("pause");
    return 0;
}

两个文本文件:

这里写图片描述

这里写图片描述

这样就完全复制到了fswrite打开的文件中。

这里get是一个字符一个字符的复制的,再给一个一行一行的复制:

#include<iostream>
#include<fstream>
#include<string.h>

using namespace std;

int main() {
#if 0
    ifstream fsr("abc.txt");
    if (!fsr)
        cout << "open error" << endl;
    else
        cout << "open success" << endl;

    ofstream fsw("bca.txt");
    if (!fsw)
        cout << "open error" << endl;
    else
        cout << "open success" << endl;
    /*char buf[1024];
    memset(buf, 0, sizeof(buf));
    while (fs.getline(buf, 1024, '\n'), !fs.eof())
        cout << buf;*/
    char ch;
    while (fsr.get(ch), !fsr.eof())
        fsw.put(ch);

    fsw.open("bac.txt", ios::in | ios::out);
#endif

    fstream fsread("read.txt", ios::in | ios::out | ios::trunc);
    fstream fswrite;
    fswrite.open("write.txt", ios::in | ios::out | ios::trunc);

    fsread << "hello world" << endl;
    fsread << "i like c" << endl;
    fsread << "i lile c++" << endl;
    fsread << "i like game" << endl;
    fsread.seekg(0, ios::beg);
    char buf[1024];
    while (fsread.get(buf, 1024, '\n'), !fsread.eof())
        fswrite << buf;

    system("pause");
    return 0;
}

会发现程序一直阻塞:

这里写图片描述

这里写图片描述

原因和C++之cin.get中说的get是一样的问题,遇到界定符‘\n’之后,停止流入,并且不会把界定符读入到缓冲区中,在下一次get时,也不会跳过界定符,会再次遇到界定符,这里就要用getline来解决。

3、成员函数getline

#include<iostream>
#include<fstream>
#include<string.h>

using namespace std;

int main() {
#if 0
    ifstream fsr("abc.txt");
    if (!fsr)
        cout << "open error" << endl;
    else
        cout << "open success" << endl;

    ofstream fsw("bca.txt");
    if (!fsw)
        cout << "open error" << endl;
    else
        cout << "open success" << endl;
    /*char buf[1024];
    memset(buf, 0, sizeof(buf));
    while (fs.getline(buf, 1024, '\n'), !fs.eof())
        cout << buf;*/
    char ch;
    while (fsr.get(ch), !fsr.eof())
        fsw.put(ch);

    fsw.open("bac.txt", ios::in | ios::out);
#endif

    fstream fsread("read.txt", ios::in | ios::out | ios::trunc);
    fstream fswrite;
    fswrite.open("write.txt", ios::in | ios::out | ios::trunc);

    fsread << "hello world" << endl;
    fsread << "i like c" << endl;
    fsread << "i lile c++" << endl;
    fsread << "i like game" << endl;
    fsread.seekg(0, ios::beg);
    char buf[1024];
    while (fsread.getline(buf, 1024, '\n'), !fsread.eof())
        fswrite << buf << endl;

    system("pause");
    return 0;
}

这时fswrite打开的文件就完全复制了fsread打开的文件内容:

这里写图片描述

注意:

由于getline会跳过界定符,所以在往fswrite流对象中写入的时候要自己加上回车符,否则文本都连在一起了,像这样:

这里写图片描述

这也算是getline的一个小小的缺陷,get(char)可以完美解决,但是如果拷贝大文件的话,效率就太低了,只能说各有优缺点吧。

上面都是单个字符的读写,或者行的读写,最后再来说一下二进制文件的以块为单位的读写:

4、二进制文件的读写

二进制文件的成块读写是通过read和write函数实现的

istream& read(char* buf, int len);
ostream& write(const char* buf, int len);
#include<iostream>
#include<fstream>
#include<string.h>

using namespace std;

struct Stu {
    char name[1024];
    char sex;
    int age;

};

int main() {

    fstream fsb("bi.binary", ios::in | ios::out | ios::trunc | ios::binary);
    Stu stu[5] = {
        {"郭靖", 'm', 18},
        {"黄蓉", 'w', 16},
        {"洪七公", 'm', 53},
        {"东邪", 'm', 46},
        {"梅超风", 'w', 35}
    };
    for (int i = 0; i < 5; i++) {
        fsb.write((char*)&stu[i], sizeof(Stu));
    }
    fsb.seekg(0, ios::beg);

    Stu s;

    while (fsb.read((char*)&s, sizeof(s)), !fsb.eof()) {
        cout << "name: " << s.name << endl;
        cout << "sex: " << s.sex << endl;
        cout << "age: " << s.age << endl;
        cout << "------------------------------" << endl;
    }
    system("pause");
    return 0;
}
fsb.write((char*)&stu[i], sizeof(Stu));

通过write函数将每个Stu对象写入到fsb打开的文件中去,这里注意必须要进行类型转换,否则报错。

while (fsb.read((char*)&s, sizeof(s)), !fsb.eof())

通过read函数循环读取出fsb打开的文件,同样需要类型转换。

输出结果:

这里写图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值