windows下使用fread/fwrite的文件指针跳转错误问题

坑的描述
用fwrite把数据写入文件,再用fread读取,发现后半部分的数据可能是错的。
原因:原本要写入文件的数据中,有0x0A,如果用的是文本模式打开的文件流,在windows下0x0A会被转换为0x0D和0x0A
其实windows下的git bash每次git add后都有类似的提示,只是一直没太注意:

先说结论
用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.

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

举例:
windows下使用fread/fwrite的文件指针跳转错误问题

图中nread为每次读的字节数,nwrite为每次写的字节数,n表示读写次数,location表示文件指针位置。
如果以“r”的方式而不是“rb”的方式打开文件,那么在读写过程中会发生图中这样的文件指针错误跳转的现象,使用"rb"后恢复正常。
具体在什么地方会发生这样的跳转还不知道原因。

引用:https://www.cnblogs.com/zjutzz/p/10500353.html