(转载)用C++中STL提供的fstream和stream_iterator读写二进制文件

(转载)http://blog.chinaunix.net/uid-22342666-id-1774790.html

[前言]
    笔者常习惯使用C库中的FILE*来操作文件,但是C++的STL中是提供了fstream等文件流对象,于是乎便刻意的改变自己的一些习惯,让程序看起来更C++一些。
    这是笔者在最近写的一个程序中的片段,由于常常把写的一些小模块给弄丢了,故在此留个记号,若对你有所帮助,欢迎常来看看~ 
    :) wangxinus, 2009.9
    
[正文]
    需要解决的问题是这样的:在一个2进制的数据文件中,整齐的排列着以6bytes对齐的数据,其实是一组指令,每一个指令都是这样的结构[命令码 操作码1 操作码2],宽度为2+2+2bytes。把这里指令读出来,然后再做其他操作。
    这个问题很简单,的确。建立一个如下的结构体:
    struct Opcode
    {
        uint16_t cmd;
        uint16_t op1;
        uint16_t op2;
    };
    然后打开文件,每次读取sizeof(struct Opcode)长度,并填入结构中,然后放入一个链表 std::list<Opcode> OpList。
    
    以前,我肯定会这么做。但是为什么我不能做得更C++一些呢?C++提供了输入输出流,流指示器(iterator:主流翻译是 迭代器)std::istream_iterator, 还有泛型算法 copy。STL提供了强大的泛型运算,那么我们就应该好好利用,写出来可以是这样的:
    std::ifstream inFile(fileName.c_str(), std::ios::in|std::ios::binary);
    std::istream_iterator<Opcode> is(inFile); 
    std::istream_iterator<Opcode> eof; 
    std::list<Opcode> thisList;
    /* 前面都是一些定义,真正完成数据读入的就是这么一句  */ 
    std::copy(is, eof, back_inserter(thisList));
    
        上面的代码还有一个问题没有解决,这个问题隐藏在copy中,因为我们的文件流还不能够识别Opcode对象,需要我们重载std::istream& operator>>(std::istream& is, Opcode& opcode);
        
    std::istream& operator>>(std::istream& is, Opcode& opcode)
    {
        is.read(reinterpret_cast<char*>(&opcode), sizeof(Opcode));
        return is;
    }
    
    这样我们就把数据全部读入内存中,然后我们可以对数据做其他处理了。同理,我们也可以把数据写入文件中。
    
[注意]
    使用fstream时, 一定要把打开文件的方式写清楚,这里是以2进制的方式打开,就需要加上std::ios::binary 标志位。如果不加,在linux上面运行没有问题,但是windows上面就出现了数据读不完的错误, 原因是在*nix系统中,并不区分文本文件和数据文件,windows却区分了,默认的是文本方式。
    
[代码]    
    附上一段测试的代码。 

 

/**********************************************************
** Copyleft (C) 2009 wangxinus
** http://wangxinus.cublog.cn
** 用C++中STL提供的fstream和stream_iterator读写二进制文件。
**********************************************************/
#include <iostream>
#include <fstream>
#include <list>
#include <string>
#include <iterator>

// 测试用的文件
const std::string fileIn = "test.jpg";
const std::string fileOut = std::string("new") + fileIn;

class Opcode
{
    public:
        //...这里定义其他操作
    private:
        uint16_t _cmd;
        uint16_t _op1;
        uint16_t _op2;
};


inline std::istream& operator>>(std::istream& is, Opcode& opcode)
{
    is.read(reinterpret_cast<char*>(&opcode), sizeof(Opcode));
    return is;
}

inline std::ostream& operator<<(std::ostream& os, const Opcode& opcode)
{
    os.write(reinterpret_cast<const char*>(&opcode), sizeof(Opcode));
    return os;
}

int main()
{
    std::ifstream in(fileIn.c_str(), std::ios::binary | std::ios::in);
    if(!in)
    {
        std::cerr << "Open In file failed!" << std::endl;
        return -1;
    }

    std::list<Opcode> opcodeList;

    //从文件中读入数据
    std::istream_iterator<Opcode> is(in);
    std::istream_iterator<Opcode> eof;
    std::copy(is, eof, back_inserter(opcodeList));

    //...这里对数据进行一些操作 <<
    std::ofstream out(fileOut.c_str(), std::ios::binary | std::ios::out);
    if(!out)
    {
        std::cerr << "Open Out file failed!" <<std::endl;
        return -1;
    }

    //把数据写入另外一个文件中
    std::ostream_iterator<Opcode> os(out, "");
    std::copy(opcodeList.begin(), opcodeList.end(), os);

    std::cout << "Write OK!" << std::endl;
    return 0;
}

 

 

 

posted @ 2013-05-06 00:09  robotke1  阅读(970)  评论(0编辑  收藏  举报