C语言fwrite多写进很多空格,C语言fread/fwrite填坑记

在Windows环境下,使用fwrite和fread操作文件时,若数据包含0x0A(换行符),在文本模式下写入并读取可能会导致数据错误。这是因为文本模式下,0x0A会被转换为0x0D0A。解决办法是使用二进制模式('wb'和'rb')进行文件操作,以确保数据的一致性。此问题在处理非字符数据如float数组时尤为关键。
摘要由CSDN通过智能技术生成

坑的描述

用fwrite把数据写入文件,再用fread读取,发现后半部分的数据可能是错的。

原因:原本要写入文件的数据中,有0x0A,如果用的是文本模式打开的文件流,在windows下0x0A会被转换为0x0D和0x0A

其实windows下的git bash每次git add后都有类似的提示,只是一直没太注意:

5cafe909c8330153d2c1cbfe9e0274a7.png

先说结论

用fread或fwrite的时候,如果是要写入字符,那么打开的文件、读取的文件,用字符模式(w和r)

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数组等,则一定要用二进制模式打开文件(wb和rb)(尽管在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下,遇到0x0A进行写入(也就是\n)会替换为0x0D和0x0A(分别是\r和\n)。

The fwrite function writes up to count items, of size length each, from buffer to the output stream. The file pointer associated with stream (if there is one) is incremented by the number of bytes actually written. If stream is opened in text mode, each linefeed is replaced with a carriage-return - linefeed pair. The replacement has no effect on the return value.

举例细说

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

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

#include

#include

#include

#include

#include

#include

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;

}

7dfd80e5496acf4985f90e45eabcf8d5.png

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

调试结果:

11c8cd67f97e43bce12fc8ac1f6a6a56.png

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

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

17f965d936d6fce0998e766156139695.png

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值