现象
以前在使用git时注意过一个现象,在本地代码中有新增或已修改的中文文件时,这时候执行命令git status
会显示出相关文件列表,如下图:
之前没有注意git是如何转换的,今天就下决心了解一下。
实战
我的操作如下:
- 在git分支下新增文件"再见.txt"
- 使用
git status
命令,可看到上图
git不直接使用汉字,而是将它转换了一下,由我们看到的,
"再见.txt" -> "\345\206\215\350\247\201.txt"
分析
转换前后再见“变成”了\345\206\215\350\247\201,我们可以简单地推算,“再”对应前三个数字,“见”对应后三个数字。即
再 -> \345\206\215
见 -> \350\247\201
那么,git是怎么处理的呢?
由一个汉字被转换成三个字节来看,git很可能使用的是utf8编码集。那就先写个程序尝试一下。三下五除二,程序主干大致如下:
String s = "再见";
byte[] bytes = s.getBytes(Charset.forName("utf-8"));
for (byte aByte : bytes) {
System.out.println(aByte);
}
程序运行结果如下:
-27
-122
-115
-24
-89
-127
幸运的是,我们把“再见”二字转成utf-8的字节后发现长度是6位,这时候我们要考虑一下-27怎么和345对应上的。 这个结果是byte类型的,我们试着把它们转成10进制输出一下。程序如下:
String s = "再见";
byte[] bytes = s.getBytes(Charset.forName("utf-8"));
for (byte aByte : bytes) {
System.out.println(aByte & 0xff);
}
将一个byte值和0xff与运算,这牵涉到数据在计算机中的存储、原码、反码、补码等概念。这次的结果是:
229
134
141
232
167
129
再次分析
345这个数字可能是16进制的,也可能是十进制的。 假设它是16进制的,那么 HEX(345)=DEC(837),837和-12不太好扯上关系,进一步假设它是十进制的,则DEC(345)=HEX(159),这两个数和-12或229还是没有扯上关系。然而,特别幸运的在网上看到一篇CSDN博客https://blog.csdn.net/MLQ8087/article/details/52174834,说到git的文件名中使用了8进制。 尝试一下发现,OCT(345)=DEC(229)!
最终程序如下:
String s = "再见";
byte[] bytes = s.getBytes(Charset.forName("utf-8"));
for (byte aByte : bytes) {
int i = aByte & 0xff;
String octalString = Integer.toOctalString(i);
System.out.println(octalString);
}
思考
- 为什么看到345的时候没有想到它本身是个八进制数呢?
其实以一种“后见之明”就可以发现“再见.txt”对应的“\345\206\215\350\247\201.txt”中没有a/b/c/d/e/f这几个字母,很大程度上(因为测试样本太少了,就“再见”两个字)说明它们不会是十六进制,没有8/9这两个数字也可能在说它本身就是一个八进制。