C语言fread/fwrite填坑记

先说结论

freadfwrite的时候,如果是要写入字符,那么打开的文件、读取的文件,用字符模式(wr

FILE* fin = fopen("filename", "w");
fread(buf, sizeof(char)*num_elem, 1, fin);
fclose(fin);
FILE *fout = fopen("filename", "r");
fwrite(buf, sizeof(char)*num_elem, 1, fout);
fclose(fout);

如果是要写入非字符的数据,例如float数组、int数组等,则一定要用二进制模式打开文件(wbrb)(尽管在linux和mac下你的结果也许一直没问题,但是保不准到了windows下会出错):

FILE* fin = fopen("filename", "wb");
fread(buf, sizeof(float)*num_elem, 1, fin);
fclose(fin);
FILE *fout = fopen("filename", "rb");
fwrite(buf, sizeof(float)*num_elem, 1, fout);
fclose(fout);

原因:字符模式打开的文件,在windows下,遇到0x0D和0x0A(分别是\r\n)会替换为0x0A进行写入(也就是\n)。

举例细说

读取图像,通常用opencv,但是考虑到arm上用opencv过于庞大,考虑在pc上把图像的数据读取出来,然后整理下顺序,再用fwrite保存。后面在arm上直接fread就行了,避开了opencv。

但在具体实现的时候发现,fwrite后再fread,只有前面一部分数据是正确的!原因如上面说的,保存到文件的是float数组,但是打开文件的模式错误的设定为了字符模式,而不是二进制模式。

#include <stdio.h>
#include <stdlib.h>

#include <iostream>
#include <string>

#include <vector>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main() {
    string im_pth = "../cat_227.jpg";
    IplImage* img = cvLoadImage(im_pth.c_str(), CV_LOAD_IMAGE_COLOR);

    int iImgChnl = 3;
    int iImgHgt = 227;
    int iImgWth = 227;
    int num_elem = iImgChnl * iImgHgt * iImgWth;
    float* pfImgData;
    pfImgData = (float*)malloc(sizeof(float)*num_elem);

    float* f_input_data_b = (float*)malloc(sizeof(float)*iImgHgt*iImgWth);
    float* f_input_data_g = (float*)malloc(sizeof(float)*iImgHgt*iImgWth);
    float* f_input_data_r = (float*)malloc(sizeof(float)*iImgHgt*iImgWth);

    for (int i = 0; i < num_elem; i += 3) {
        f_input_data_b[i / 3] = (float)(unsigned char)(img->imageData[i]);
        f_input_data_g[i / 3] = (float)(unsigned char)(img->imageData[i + 1]);
        f_input_data_r[i / 3] = (float)(unsigned char)(img->imageData[i + 2]);
    }

    for (int i = 0; i < iImgHgt*iImgWth; i++) {
        pfImgData[i] = f_input_data_b[i];
    }
    for (int i = 0; i < iImgHgt*iImgWth; i++) {
        pfImgData[i + iImgHgt*iImgWth] = f_input_data_g[i];
    }
    for (int i = 0; i < iImgHgt*iImgWth; i++) {
        pfImgData[i + 2*iImgHgt*iImgWth] = f_input_data_r[i];
    }
    int ret;

    string save_pth = "../cat_227.fread_float.w";
    FILE* fout = fopen(save_pth.c_str(), "w");
    ret = fwrite((void*)pfImgData, sizeof(float), num_elem, fout);
    fclose(fout);

    printf("--- pfImgData[5847]=%f, pfImgData[5848]=%f\n", pfImgData[5847], pfImgData[5848]);

    //--------------------------------------------------
    float* tuopan = (float*)malloc(sizeof(float)*num_elem);
    FILE* fin = fopen(save_pth.c_str(), "rb");
    ret = fread((void*)tuopan, sizeof(float), num_elem, fin);
    fclose(fin);

    printf("--- tuopan[5847]=%f, tuopan[5848]=%f\n", tuopan[5847], tuopan[5848]);

    printf("--- check here---\n");

    return 0;
}

cat_227.jpg

测试环境:VS2013 update5, win32/x64 debug/release模式

调试结果:

监视变量

发现第5848个元素是错误的。

通过分别设定字符模式和二进制模式来写入文件,看到了差异:
对比二进制文件

第一次出现差异的地方是0x5B60后的一个元素,0x5B60恰好是十进制下的23392,23392=5848 x 4, 4表示sizeof(float)

猜你喜欢

转载自www.cnblogs.com/zjutzz/p/10500353.html