坑的描述

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

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

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

先说结论

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下,遇到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.

ref:https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/fwrite?view=vs-2017

举例细说

读取图像,通常用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;
}

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

调试结果:

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

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

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

C语言fread/fwrite填坑记的更多相关文章

  1. UiAutomator2.0升级填坑记

    UiAutomator2.0升级填坑记 SkySeraph May. 28th 2017 Email:skyseraph00@163.com 更多精彩请直接访问SkySeraph个人站点:www.sk ...

  2. Android项目开发填坑记-Fragment的onBackPressed

    Github版 CSDN版 知识背景 Fragment在当前的Android开发中,有两种引用方式,一个是 Android 3.0 时加入的,一个是supportV4包中的.这里简称为Fragment ...

  3. Android项目开发填坑记-Fragment的onAttach

    背景 现在Android开发多使用一个Activity管理多个Fragment进行开发,不免需要两者相互传递数据,一般是给Fragment添加回调接口,让Activity继承并实现. 回调接口一般都写 ...

  4. Android项目开发填坑记-so文件引发的攻坚战

    故事的最初 我负责的项目A要求有播放在线视频的功能,当时从别人的聊天记录的一瞥中发现百度有相关的SDK,当时找到的是Baidu-T5Player-SDK-Android-1.4s,项目中Demo的so ...

  5. minikube windows hyperx填坑记

    minikube windows hyperx填坑记 安装了一天半,还是没行,先放弃 开始 minikube start --vm-driver=hyperv --hyperv-virtual-swi ...

  6. 浅谈html5 video 移动端填坑记

    这篇文章主要介绍了浅谈html5 video 移动端填坑记,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 本文介绍了html5 video 移动端填坑记,分享给大家,具体 ...

  7. Java web 开发填坑记 2 -如何正确的创建一个Java Web 项目

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/72566261 本文出自[赵彦军的博客] Java web 开发填坑记 1-如何正确 ...

  8. Appium+python自动化(十三)- 输入中文 - 一次填坑记(超详解)

    简介 无论你在哪里,在做什么都会遇到很多坑,这些坑有些事别人挖的,有些是自己挖的.别人挖的叫坑人,自己挖的叫自杀,儿子挖的叫坑爹.因此在做app自动化道路上也不会是一帆风顺的,你会踩很多坑,这些坑和你 ...

  9. Cloudera Manager 5.9 和 CDH 5.9 离线安装指南及个人采坑填坑记

    公司的CDH早就装好了,一直想自己装一个玩玩,最近组了台电脑,笔记本就淘汰下来了,加上之前的,一共3台,就在X宝上买了CPU和内存升级了下笔记本,就自己组了个集群. 话说,好想去捡垃圾,捡台8核16线 ...

随机推荐

  1. Linux(Ubuntu)使用日记------ssh远程登录腾讯云

    不知道是我自己电脑的问题还是其他的问题.总之在我的折腾之下算是用ssh连接上了我的腾讯云. 具体步骤: 1.生成密钥 ssh-keygen -t rsa 执行命令会出现这样,执行后让你输入东西的全部回 ...

  2. Win10图片打不开文件系统错误2147416359解决方法

    该问题表现为win10打开所有图片都会提示这个‘文件系统错误-2147416359’,打开其他文件没问题.此问题应该是win10自带的图片查看器出了故障. 在网上找到如下方案,但是我的服务列表里没有这 ...

  3. kotlin电商学习记录,好久没来逛逛了

    好久没来,一直做毕业设计,用kotlin写一个基于以图搜图的购物app,现在又赶上实习,内容多,时间少,不过前途光明并由贵人指点.加油 kotlin电商学习记录 技术选型 视图层 kotlin-and ...

  4. FastDFS分布式文件系统客户端安装

    软件安装前提:服务器已配置好LNMP环境安装libfastcommon见FastDFS服务器安装文档(http://www.cnblogs.com/Mrhuangrui/p/8316481.html) ...

  5. c 判断文件或文件夹是否存在,多种方法, 为什么从一开始就不直接来个统一的呢?

    具体内容,请看: https://blog.csdn.net/u012494876/article/details/51204615 判断文件或文件夹是否存在,竟然有这么多方法: GetFileAtt ...

  6. Go语言系列(八)- Goroute和Channel

    一.Goroute 1. 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配合调度的一个独立单位 B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能 ...

  7. ArcGis安装失败提示“需要Microsoft .NET Framework 3.5 sp1或等效环境”的解决方法

    这个问题一般出现在Win8或者Win10系统上,因为系统默认没有启用该.Net Framework. 下载Microsoft .NET Framework 3.5 sp1安装后再开始安装ArcGis. ...

  8. SpringBoot系列: 使用 Swagger 生成 API 文档

    SpringBoot非常适合开发 Restful API程序, 我们都知道为API文档非常重要, 但要维护好难度也很大, 原因有: 1. API文档如何能被方便地找到? 以文件的形式编写API文档都有 ...

  9. A fine property of the non-empty countable dense-in-self set in the real line

    A fine property of the non-empty countable dense-in-self set in the real line   Zujin Zhang School o ...

  10. ssh远程登陆脚本(带跳板机)

    mac自带的终端不太好用,被推荐了一个iterm2的终端替代工具,确实比自带的终端好用不少.下面记录下通过脚本一键远程登录的过程: 下载地址:http://m4.pc6.com/xuh3/iTerm2 ...