• (转载)用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;
    }
  • 相关阅读:
    ORACLE 定时执行存储过程
    Java 基于spring 暴露接口 供外部调用
    java 从jsp页面传集合给controller
    Java 后台验证的工具类
    Xcode12真机/模拟器运行项目非常慢的解决方式
    苹果手机系列 安全区高度/设置粗体高度不正常
    Xcode 官方下载地址
    OC UICollectionView 滚动完全显示item
    cocospod 更新到指定版本及其问题
    OC 一张图片填充满整个导航栏(包含X系列)
  • 原文地址:https://www.cnblogs.com/Robotke1/p/3061968.html
Copyright © 2020-2023  润新知