• C/C++文件操作经验总结


    最近在做一个从groundtruth_rect.txt中读取按行存储的矩形元素(x, y, w, h),文本存储的格式如下:

    310,102,39,50
    308,100,39,50
    306,99,39,50
    306,98,38,49
    304,97,38,49
    303,96,37,48

    一般处理这种带格式的存储数据,我最喜欢的就是C语言中的格式化的输出和输入fprintf和fscanf,因为知道格式,所以一个循环反复就可以将矩形从txt中提取出来,非常的简单方便。可是当我定义了一个FILE* file = fopen("groundtruth_rect.txt","r");时程序总是有一个bugger,编译器(VS2010)输出的错误信息是:

    error C2679: 二进制“=”: 没有找到接受“FILE *”类型的右操作数的运算符(或没有可接受的转换)
    1>          C:Program Files (x86)Microsoft SDKsWindowsv7.0Aincludewinbase.h(6618): 可能是“_WIN32_FIND_DATAA &_WIN32_FIND_DATAA::operator =(const _WIN32_FIND_DATAA &)”

    调来调去也没有找到错误原因,在网上也没有找到相关的提示。我猜测原因可能是由于在程序中定义了和包含了一下东西以方便我能够进行文件夹下的序列图像的路径获取:

    #define _AFXDLL
    #define _WIN32_WINNT 0x0502 
    #include <WinBase.h>
    #include <ShlObj.h>
    #include <afxdlgs.h>
    #include <atlstr.h>


    (如果有“同道中人”希望能指点一二)

    如果去掉上面的那一部分所有的bugger就消失了。因为必须用到上面获取路径的办法,所以只好放弃使用FILE *这种C语言的文件操作,转而使用C++提供的文件操作方法:

    string line;
    getline(file, line);
    istringstream linestream(line);
    string x1, y1, w1, h1;
    getline(linestream, x1, ',');
    getline(linestream, y1, ',');
    getline(linestream, w1, ',');
    getline(linestream, h1, ',');
    int x = atoi(x1.c_str());
    int y = atoi(y1.c_str());
    int w = atoi(w1.c_str());
    int h = atoi(h1.c_str());
    groundtruth_rect[i] = Rect(x, y, w, h);

    上面这段代码是一种比较好的方法,在运行中没有出现错误。采用的完全是按照字符来对待,以 ‘,’ 作为行的getline的结尾,一行一行的读取数据,然后再利用atoi()将字符串转变为数字,也就实现了格式化读取数据的目的。
    下面先给出使用getline的范例
    <span style="font-size:18px;">// string_getline_sample.cpp
    // compile with: /EHsc
    // Illustrates how to use the getline function to read a
    // line of text from the keyboard.
    //
    // Functions:
    //
    //    getline       Returns a string from the input stream.
    //////////////////////////////////////////////////////////////////////
    
    #pragma warning(disable:4786)
    #include <string>
    #include <iostream>
    
    using namespace std ;
    
    int main()
    {
       string s1;
       cout << "Enter a sentence (use <space> as the delimiter): ";
       getline(cin,s1, ' ');
       cout << "You entered: " << s1 << endl;;
    }</span>

    然后再给出atoi()的使用范例:atoi会把能够解释为数字的字符串转变为整形数据,从字符串的开头一直到第一个不能被解释为数字的字符为止,比如“”等。

    <span style="font-size:18px;">// crt_atoi.c
    // This program shows how numbers 
    // stored as strings can be converted to
    // numeric values using the atoi functions.
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    
    int main( void )
    {
        char    *str = NULL;
        int     value = 0;
    
        // An example of the atoi function.
        str = "  -2309 ";
        value = atoi( str );
        printf( "Function: atoi( "%s" ) = %d
    ", str, value );
    
        // Another example of the atoi function.
        str = "31412764";
        value = atoi( str );
        printf( "Function: atoi( "%s" ) = %d
    ", str, value );
    
        // Another example of the atoi function 
        // with an overflow condition occuring.
        str = "3336402735171707160320";
        value = atoi( str );
        printf( "Function: atoi( "%s" ) = %d
    ", str, value );
        if (errno == ERANGE)
        {
           printf("Overflow condition occurred.
    ");
        }
    }</span>

    输出为:
    Function: atoi( "  -2309 " ) = -2309
    Function: atoi( "31412764" ) = 31412764
    Function: atoi( "3336402735171707160320" ) = 2147483647
    Overflow condition occurred.


    但一开始并没有想到这种方法,而是采用了一个比较笨的办法,刚开始还能正确读取数据,可是读到一半的时候居然读出的数据全是0了,我也真是快疯了(本来痛痛快快的使用C中的格式化输入就好了,结果搞了两个小时才搞定,心情郁闷可想而知)

    //int  test[4];

    //test[0] = 0;
    //file>>dec>>test[0];
    //groundtruth_rect[i].x = test[0];

    //test[1] = 0;
    //file.seekg(1,ios::cur);
    //file>>dec>>test[1];
    //groundtruth_rect[i].y = test[1];

    //test[2] = 0;
    //file.seekg(1,ios::cur);
    //file>>dec>>test[2];
    //groundtruth_rect[i].width = test[2];

    //test[3] = 0;
    //file.seekg(1,ios::cur);
    //file>>dec>>test[3];
    //groundtruth_rect[i].height = test[3];
    //file.seekg(1,ios::cur);

    采用的方法是运算符>>,中间的dec是表示采用十进制的方式输入,插入器(>>)+操纵符(dec)的方式,刚开始并没有加file.seekg(1,ios::cur);进行文件的重定位,除了第一个之外后面读到的数据全是0,我就这样一步一步的通过调试(不太熟悉这个机制,又急着实现,只能盲人摸象了)。后来采用了file.seekg(1,ios::cur);来对文件的读位置进行定位,跳过了格式化作用的逗号,就这样才能正确的读入了。结果开始运行后,发现一共500多个矩形框的数据,这种方式只能读取到221个,而且读出的数据是对的,但是后面的200多个就不知道为啥读不进来了。这个bugger也依然没有解决(希望有高人指点迷津)!

    有了以上的调试经历,我感觉到不能再盲人摸象,便决定对C++的典型文件操作进行一下学习和总结:

    具体内容可以参看了别人的博文,我下面只对比较常用的内容进行介绍:http://blog.csdn.net/jiangxinyu/article/details/7875931 和 http://www.cnblogs.com/kzloser/archive/2012/07/16/2593133.html

    不管是Linux(shell)还是windows下,一般默认打开的输入输出设备对象都会有三种:一是标准输入设备键盘缓冲区,二是标准输出设备显示器缓冲区,三是错误信息。(特别是在linux下的shell命令,很经典的对照,有兴趣的可以了解一下,输入输出重定向的方法是不是类似c++中的iostream与fstream,ofstream,ifstream)。

    当然首先就是打开文件,一般都会有文本文件和二进制文件的选项,默认大都是文本文件,C语言中的“wb+” b表示为二进制,而C++中为ios::binary
    C++有
    操纵符 功能 输入/输出
    dec 格式化为十进制数值数据 输入和输出
    endl 输出一个换行符并刷新此流 输出
    ends 输出一个空字符 输出
    hex 格式化为十六进制数值数据 输入和输出
    oct 格式化为八进制数值数据 输入和输出
    setpxecision(int p) 设置浮点数的精度位数 输出
    对应到C中有格式化的输入输出:%c,%d,%f,%s等等。

    另外与C的文件操作方式不太一样的地方是C++管理读指针和写指针,分别可以利用seekg和seekp来设定
    ios::beg:  文件开头
    ios::cur:  文件当前位置
    ios::end:  文件结尾
    而对应到C则是fseek(),ftell等。
    C的文件操作总结如下:


    C++经典的文件操作如下:



    *******************************************************************************************************************************************************************************************************2015-7-24

  • 相关阅读:
    密码保护
    实现搜索功能
    完成个人中心—导航标签
    个人中心标签页导航
    评论列表显示及排序,个人中心显示
    完成评论功能
    从首页问答标题到问答详情页
    首页列表显示全部问答,完成问答详情页布局
    Android基础学习:Android环境搭建
    liunx 硬盘分区
  • 原文地址:https://www.cnblogs.com/huty/p/8519297.html
Copyright © 2020-2023  润新知