C++文件流操作与流缓冲重定向

本文转自http://www.cnblogs.com/kex1n/archive/2012/01/06/2314985.html,作者:小楼一夜听春雨


我们使用STL编程的时候有时候会想到把一个流对象指向的内容用另一个流对象来输出,比如想把一个文件的内容输出到显示器上,我们可以用简单的两行代码就可以完成。

ifstream infile("test.txt");
cout << infile.rdbuf();

上面的代码就把infile流对象中的流重定向到标准输出cout上,您可以在屏幕上看到test.txt的内容。

下面的例子来自MSDN,清晰的描述了rdbuf函数的使用方法


// basic_ios_rdbuf.cpp 
// compile with: /EHsc 
#include <ios> 
#include <iostream> 
#include <fstream> 
int main( ) 
{ 
    using namespace std; 
    ofstream file( "rdbuf.txt" ); 
    streambuf *x = cout.rdbuf( file.rdbuf( ) ); 
    cout << "test" << endl; // Goes to file
    cout.rdbuf(x); 
    cout << "test2" << endl;
 }

rdbuf函数有两种调用方法:

1)basic_streambuf<Elem, Traits> *rdbuf( ) const;
     无参数。返回调用者的流缓冲指针。

2)basic_streambuf<Elem, Traits> *rdbuf( basic_streambuf<E, T> *_Sb);
      参数为流缓冲指针。它使调用者与参数(流缓冲指针)关联,返回自己当前关联的流缓冲区指针。


假如我们用C语言写一个文件复制程序,比如一个mp3文件,我们首先考虑的是C语言的文件输入输出功能,其思路是建一个指定大小缓冲区,我们从源文件中循环读取缓冲区大小的数据,然后写进目的文件。而在C++中,我们抛弃了这种用字符缓冲区的按字节复制的方法,因为这种方法看起来很繁琐,而且效率一点也不高。下面可以对比这两种方法(程序可以直接执行):


C:

#include<stdlib.h>
#include<stdio.h>
int main()
{
    char buf[256];
    FILE *pf1, *pf2;
    if((pf1 = fopen("1.mp3", "rb")) == NULL)
    {
        printf("源文件打开失败/n");
        return 0;
    }
    if((pf2 = fopen("2.mp3","wb")) == NULL)
    {
        printf("目标文件打开失败/n");
        return 0;
    }
    while(fread(buf,1,256,pf1), !feof(pf1))
    {
        fwrite(buf,1,256,pf2);
    }
    fclose(pf1);
    fclose(pf2);
    return 0;
}

C++:

#include<fstream>
#include<iostream>
using namespace std;
int main()
{
    fstream fin("1.mp3",ios::in|ios::binary);
    if(!fin.is_open())
    {
        cout << "源文件打开失败" << endl;
        return 0;
    }
    fstream fout("2.mp3",ios::out|ios::binary);
    if(! fin.is_open())
    {
        cout << "目标文件打开失败!" << endl;
        return 0;
    }
    fout<<fin.rdbuf();
    fin.close();
    fout.close();
    return 0;
} 

看起来是不是清晰多了呢,这就是C++中的流缓冲的威力了,程序通过把源文件的流重定向到关联到目的文件的流对象,通过 fout<<fin.rdbuf();一句代码就完成了在C语言中的循环读写缓冲区的功能,而且C++中使用的是底层的流缓冲,效率更高!

另外两个关于流操作与重定向的代码示例:

#include <iostream>
#include <fstream>
#include <cassert>

using namespace std;
int main()
{
    ifstream in("test.txt");
    assert(in.is_open());

    //基地址为文件结束处,偏移地址为0,于是指针定位在文件结束处
    in.seekg(0, ios::end);
    //sp为定位指针,因为它在文件结束处,所以也就是文件的大小
    streampos sp = in.tellg();    
    cout<<"file size:"<<endl<<sp<<endl;

    //基地址为文件末,偏移地址为负,于是向前移动sp/3个字节
    in.seekg(-sp/3, ios::end);   
    streampos sp2 = in.tellg();
    cout<<"from file to point:"<<endl<<sp2<<endl;

     //基地址为文件头,偏移量为0,于是定位在文件头; 从头读出文件内容
    in.seekg(0, ios::beg);
    cout<<in.rdbuf()<<endl;    

    //从sp2开始读出文件内容
    in.seekg(sp2);
    cout<<in.rdbuf()<<endl; 

    in.close();
    return 0;
}

#include <iostream>
#include <fstream>
#include <cassert>
#include <streambuf>

int main(void)
{
    std::ofstream log("test.txt");
    assert(log.is_open());

    // 返回cout原来的的流缓冲指针,使cout重定向到log文件的流缓冲
    std::streambuf* x = std::cout.rdbuf(log.rdbuf());

    // 写入到文件中
    std::cout << "xiaolouyiyetingchunyu\n";

    log.close();

    std::cout.rdbuf(x);           // 恢复cout的流对象指针

    std::cout << "yuanyuewandao\n";       // 写入cout

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值