【C++】小心使用文件读写模式:回车('\r') 换行('\n')问题的一次纠结经历
原来没有仔细注意C++读写文件的二进制模式和文本模式,这次吃了大亏。(平台:windows VS2012)
BUG出现:
写了一个程序A,生成一个文本文件F保存在本地,然后用程序B读取此文件计算MD5值。
将该文件上传到服务器,再用程序B将文件从服务器上下载下来计算MD5值,神奇的发现两次计算的MD5值不一样,文件被谁改了??
排除问题:
1.首先对比了生成文件F和上传到服务器的文件,发现文件复制过程无差错,是同一个文件。
2.用程序B下载文件F后,保存在本地,发现文件与原文件F不一致,对比二进制发现每行多了一个\r。
3.怀疑服务器传输前对文件格式进行了更改,用wireshark抓包,发现文件内容与服务器上文件一致。那么这个多出来的\r从何而来呢,行结尾变成了\r\r\n。
4.查看文件F,行结尾是\r\n,而我记得当初生成文件的时候是以\n作为换行符的,纠结一番后想起来了文件读写的模式,只记得是文本与二进制的区别,没有想起来换行符的问题。
5.几经纠结,查阅C++ primer plus后恍然大悟,都是默认使用文本模式读写文件惹的祸:windows下,文本模式会将\n输出成\r\n,读取时也会将\r\n变成一个\n;所以开始程序B读取文件F并且计算MD5时,是以\n来计算的。然而当从服务器上下载下来时,文件是以\r\n作为行结尾的,直接计算MD5会导致值不一样。而将下载下来的文件保存时,由于仍然使用的文本模式,将\r\n变成了\r\r\n,导致了当初匪夷所思的结果。
总结:
这BUG从出现到调查各方面的原因排除花费了大量的时间,说到底还是因为基础不扎实,这里讲《C++ primer plus》的关键一段话抄下来作为提醒。
“使用二进制文件模式时,程序将数据从内存传递给文件(反之亦然)时,将不会发生任何隐藏的转换,而默认的文本模式并非如此。例如,对于Windows文本文件,他们使用两个字符的组合吧(回车和换行)表示换行符;Mac文本文件使用回车表示换行符;而UNIX和Linux文件使用换行来表示换行符。C++是从UNIX系统上发展而来的,因此也使用换行来表示换行符。为增加可移植性,Windows C++程序在写文本模式文件时,自动将C++换行符转换为回车和换行;Mac C++程序在写文件时,将换行符转换为回车。在读取文本文件时,这些程序将本地换行符转换为C++模式。对于二进制数据,文本格式会引起问题,因为double值中间的字节可能与换行符的ASCII码有相同的位模式。另外,在文件末尾的检测方式也有区别。因此以二进制格式保存数据时,应使用二进制文件模式。”
后续验证:
后来写了一个小程序验证了一下所知,不懂的话可以复制下来跑一下,注意是Windows平台,生成的文件可以用wxHexEditor来查看以二进制形式查看。另外再说一点题外的,不用语言的字符串类型编码可能会不同,例如JavaScript里是UTF-16,而C++默认的是ANSI,下载下来同一个文件计算MD5值的话可能会有问题。
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{ string str1 = "hello!\n";
ofstream fout("file1");//默认文本模式
fout << str1;
fout.close(); ifstream fin("file1");
char ch = ;
string temp;
if (fin) {
while (fin.get(ch))
temp += ch;
cout << "读入file1长度:"<<temp.length() <<endl;
fin.close();
} string temp2;
fin.open("file1", ios::binary);//以\n作为换行
getline(fin, temp2);
cout << "二进制模式getline读入file1的长度(结尾包含了\\r):" << temp2.length() << endl;
fin.close(); ofstream fout2("file2");
fout2 << "hello!\r\n";
fout2.close(); string temp3;
fin.open("file2");
if (fin) {
getline(fin, temp3);
cout << "文本模式getline读入file2的长度(同样多了一个\\r):" << temp2.length() << endl;
} return ;
}
by ascii0x03, 2015.9.25
相关文章:http://blog.csdn.net/xiaofei2010/article/details/8458605/
【C++】小心使用文件读写模式:回车('\r') 换行('\n')问题的一次纠结经历的更多相关文章
- python文件读写模式 --- r,w,a,r+,w+,a+,rb,wb
要了解文件读写模式,需要了解几种模式的区别,以及对应指针 r : 读取文件,若文件不存在则会报错 w: 写入文件,若文件不存在则会先创建再写入,会覆盖原文件 a : 写入文件,若文件不存在则会先创建再 ...
- python 文件读写模式r,r+,w,w+,a,a+的区别(附代码示例)
如下表 模式 可做操作 若文件不存在 是否覆盖 r 只能读 报错 - r+ 可读可写 报错 是 w 只能写 创建 是 w+ 可读可写 创建 是 a 只能写 创建 否,追加写 a+ 可读可写 创建 ...
- python3的文件读写模式
任何一种语言,文件的读写都是非常常见的.python的文件读写非常简单,仅仅一个函数open(file也可以,但是我不常用). 先看看官网的解释: open(file, mode='r', buffe ...
- 一篇搞懂python文件读写操作(r/r+/rb/w/w+/wb/a/a+/ab)
关于文件操作的几种常用方式,网上已有很多解说,内容很丰富,但也因此有些杂乱复杂.今天,我就以我个人的学习经验写一篇详细又易懂的总结文章,希望大家看完之后会有所收获. 一.核心功能 ‘r’ ...
- Python文件读写模式
r 打开只读文件,该文件必须存在. r+ 打开可读写的文件,该文件必须存在.可读,可写,可追加. w 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失.若文件不存在则建立该文件. w+ 打 ...
- 正确理解Python文件读写模式字w+、a+和r+
w+ 和 r+的差别不难理解.还有a+ +同一时候读写,就可以读又可写,边写边读.边读边写,不用flush,用seek 和 tell可測得. fp = open("a.txt", ...
- python 文件读写模式区别,以及如何边写入边保存flush()
如表: 模式 可做操作 若文件不存在 是否覆盖 r 只能读 报错 - r+ 可读可写 报错 是 w 只能写 创建 是 w+ 可读可写 创建 是 a 只能写 创建 否,追加写 a+ 可读可写 创建 否, ...
- Python之文件读写
本节内容: I/O操作概述 文件读写实现原理与操作步骤 文件打开模式 Python文件操作步骤示例 Python文件读取相关方法 文件读写与字符编码 一.I/O操作概述 I/O在计算机中是指Input ...
- PHP文件读写操作之文件写入代码
在PHP网站开发中,存储数据通常有两种方式,一种以文本文件方式存储,比如txt文件,一种是以数据库方式存储,比如Mysql,相对于数据库存储,文件存储并没有什么优势,但是文件读写操作在基本的PHP开发 ...
随机推荐
- [NPM] Run npm scripts in series
After creating several npm script it becomes useful to run multiple scripts back-to-back in series. ...
- Net程序调试
Net程序调试 前言 作为一个.net开发工程师,不管是在写桌面程序.服务程序或web程序,在开发阶段,我们必须非常熟悉vs的动态调试技能,当然web程序可能还需要调试前端的脚本或样式,这不在本文的讨 ...
- PatentTips - Heterogeneous Parallel Primitives Programming Model
BACKGROUND 1. Field of the Invention The present invention relates generally to a programming model ...
- BFKit:对常用 UIButton,UIColor,UIDevice,UIFont ,UIImage 等开发类进行了扩展
BFKit对常用于开发的类进行了扩展,整合了多个常用的控件和开发所需要的功能,是一个通用性的类库.集成后可以帮助更快的App开发.有兴趣的同学可以看看哦. http://code4app.com/io ...
- hbase 从hbase上读取数据写入到hdfs
Mapper package cn.hbase.mapreduce.hb2hdfs; import java.io.IOException; import org.apache.hadoop.hbas ...
- 跟我学CMD实战系列之二 ——数据压缩备份
需求:每天下班时,将本地硬盘上的projects目录压缩为rar文件,文件名中必须含有当天日期信息,例如projects_20070902.rar. 分析:1. 压缩可以调用WinRAR的命令行版本r ...
- 分位数和分位线(Quantiles and Percentiles)
分位数有种积分(累积)的含义在. 分位数(即将数据由低至高排列,小于该数的数据占总体的比例达到时最终落到的数): 10%:3000元 20%:5200元 50%:20000元 80%:41500元 9 ...
- 十分钟了解 spring cloud
1 为什么需要服务发现 简单来说,服务化的核心就是将传统的一站式应用根据业务拆分成一个一个的服务,而微服务在这个基础上要更彻底地去耦合(不再共享DB.KV,去掉重量级ESB),并且强调DevOps和快 ...
- Delphi程序员如何找到高薪的工作?(赚不到钱,原因只有一个,就是他们没有被公司录取。Delphi必须要独自进行深入研究,才能精通,同时也不能自由性太强)
转帖自:http://www.tommstudio.com/ViewNews.aspx?ID=187http://hi.baidu.com/rarnu/blog/ 本文翻译自<美国优秀经理观念大 ...
- Java--垃圾收集算法及内存分配策略
本篇博客,主要介绍GC的收集算法以及根据算法要求所得的内存分配策略! 一.收集算法 收集算法,主要包括四种,分别是:Mark-Sweep(标记-清除).Copying(复制).Mark-Compact ...