一. 缘来缘起
最近,同事遇到一个非常奇怪的问题,花了0.5小时,还没有头绪,而且,越想越奇怪。
我刚好路过,感兴趣地问了一下,然后直接用一个xxd命令搞定问题,于是,皆大欢喜。
二. 奇怪问题
原问题相对复杂,为了便于叙述,我来简化一下问题。
a.txt和b.txt文件内容如下:
咦?这两个文件一模一样啊。但是,问题是,相同程序在读取它们时,出现了不同的结果。
读取a.txt第一行,发现长度为3:#include <fstream>
#include <string>
#include <iostream>
using namespace std;
int main()
{
ifstream in("a.txt");
string filename;
string line;
if(in) // 有该文件
{
while (getline (in, line)) // line中不包括每行的换行符
{
cout << line.size() << endl; // 结果为3
}
}
else // 没有该文件
{
cout <<"no such file" << endl;
}
return 0;
}
读取b.txt第一行,发现长度为6:
#include <fstream>
#include <string>
#include <iostream>
using namespace std;
int main()
{
ifstream in("b.txt");
string filename;
string line;
if(in) // 有该文件
{
while (getline (in, line)) // line中不包括每行的换行符
{
cout << line.size() << endl; // 结果为6
}
}
else // 没有该文件
{
cout <<"no such file" << endl;
}
return 0;
}
真的是非常奇怪啊!相同的文件,相同的读取程序,最后得到的结果居然不一样,究竟是什么原因呢?
很多时候,在开发中,我们会遇到类似问题,各方面现象相互矛盾,所以,有必要找出真象和假象。
三. 大胆假设
根据经验,其实我大概猜到了,原因可能是:a.txt和b.txt并不是真的一样。
上面所看到的一致的现象,只是假象,眼见不一定为实。经验证,果真如此。
四. 小心求证
直接看它们的二进制码吧,方法有很多。本文来介绍一个实用的linux命令,即xxd,来man xxd一下:
ubuntu@VM-0-15-ubuntu:~$ man xxd
XXD(1) XXD(1)
NAME
xxd - make a hexdump or do the reverse.
SYNOPSIS
xxd -h[elp]
xxd [options] [infile [outfile]]
xxd -r[evert] [options] [infile [outfile]]
DESCRIPTION
xxd creates a hex dump of a given file or standard input. It can also convert a hex dump back to its
original binary form. Like uuencode(1) and uudecode(1) it allows the transmission of binary data in a
`mail-safe' ASCII representation, but has the advantage of decoding to standard output. Moreover, it
can be used to perform binary file patching.
可以看到,xxd命令可以输出十六进制码,也可以做相反的操作。
直接来看xxd命令的结果:
ubuntu@VM-0-15-ubuntu:~$ xxd a.txt
00000000: 6162 63 abc
ubuntu@VM-0-15-ubuntu:~$ xxd b.txt
00000000: efbb bf61 6263 ...abc
ubuntu@VM-0-15-ubuntu:~$
果然,他们的二进制层面是不一致的,也就是说,a.txt和b.txt只是看起来一样,像个双胞胎,但本质并不一样。
为什么会这样呢?因为文件编码格式不同,有兴趣的朋友,可以去了解下BOM编码。那么,怎样构造BOM编码的文件呢?
编辑器都有"另存为"功能,直接把文件存为BOM编码格式,然后文件头就会多出ef bb bf,google一下,可以搜到更多有用信息:
找到了问题,解决起来就简单多了,直接统一为无BOM编码的格式即可。
顺便介绍另一个linux命令,即hexdump,它也可达到类似效果,如下:
ubuntu@VM-0-15-ubuntu:~$ hexdump a.txt
0000000 61 62 63
0000003
ubuntu@VM-0-15-ubuntu:~$ hexdump b.txt
0000000 ef bb bf 61 62 63
0000006
ubuntu@VM-0-15-ubuntu:~$
五. 最后的话
在实际工作中,熟练掌握各种调试工具,尤为重要。大胆假设,小心求证。关于linux的xxd命令,先介绍到这里。
后续也会更多地分享实战调试经验,秒杀bug, 希望大家一起进步。一个命令,节省0.5小时,这样才能少加班哈。
这篇文章,很简单,重要的不是结论具体是什么,而是解决问题的过程和方法。