编码又闹出了小问题

来源:互联网 发布:钟南山 知乎 编辑:程序博客网 时间:2024/04/27 15:47

编码总是让我感到烦恼,这次又有点小麻烦~~

import java.io.File;import java.util.Scanner;public class ScannerFileTest{    public static void main(String[] args) throws Exception{        //将一个File对象作为Scanner的构造器参数,Scanner读取文件内容        Scanner sc = new Scanner(new File("ScannerFileTest.java"));         System.out.println("ScannerFileTest.java文件内容如下:");        while(sc.hasNextLine()){            //输出文件中的下一行            System.out.println(sc.nextLine());        }    }}

经上次的教训,之后在编译时,我总这么敲命令:javac -d . -encoding utf-8 *.java
编译通过让我觉得在正常不过了,但之后运行给我带来的惊喜不是一点点
这里写图片描述
文件的内容蒸发了?

其实在敲这个之前,我根据题目信息自己写了个。而问题就在这,我的代码正常编译,运行结果也如我所料输出了文件内容。为什么这个基本一致的代码却存在问题?对比一下,大的出入就在注释,我一句都没写(个人没什么习惯写注释)。于是我把这个上面的注释加到我原来自己写的代码上,问题就来了。我尝试把中文去掉改成一些胡乱的字母串才发现,又是编码的问题……

上次同样是编码问题,说过使用ANSI编码能在不使用-encoding参数情况下通过编译,于是我把Notepad++编码改为ANSI。编译后运行,果然没问题。

要么以后就用ANSI编码算了,虽然网上多数推荐UTF-8,但也不知道为什么要这样做。有了这样的想法后,还是看了几篇关于ANSI,UTF-8,Unicode等的资料。再回来看代码,突然地,想起这几个IO类好像曾经见过在构造函数参数列里写有字符编码的参数。

于是抱着好奇心在原代码上做了些小改动:

Scanner sc = new Scanner(new File("ScannerFileTest.java") , "UTF-8");

再按照老套路编译运行,得出我想要的结果了。

搞笑,去看了下API文档,Scanner果真有这么一个构造器

Scanner
public Scanner(InputStream source,
String charsetName)构造一个新的 Scanner,它生成的值是从指定的输入流扫描的。来自该流的字节通过指定字符集转换成字符。
参数:
source - 要扫描的输入流
charsetName - 用于将来自该流的字节转换成要扫描的字符的编码类型
抛出:
IllegalArgumentException - 如果指定字符集不存在

之后又瞥了一眼原先使用的构造器

Scanner
public Scanner(InputStream source)构造一个新的 Scanner,它生成的值是从指定的输入流扫描的。取自该流的字节通过底层平台的默认字符集转换成字符。
参数:
source - 要扫描的输入流

我好奇默认字符集,点开查看

defaultCharset
public static Charset defaultCharset()
返回此 Java 虚拟机的默认 charset。
默认 charset 在虚拟机启动时决定,通常根据语言环境和底层操作系统的 charset 来确定。
返回:
默认 charset 的 charset 对象
从以下版本开始:
1.5

这是一个java.nio.charset.Charset类的静态方法,我将原来的代码又稍作修改添加了:

System.out.println(Charset.defaultCharset());

运行后发现,原来一直以来,我都用着这该死的GBK
这里写图片描述

那如果ANSI编码没有产生问题,那这GBK跟ANSI究竟有什么关系?兼容?
我查了下,有个总结很简单易懂,引用过来

所谓的「ANSI」指的是对应当前系统 locale 的遗留(legacy)编码。[1]
所谓的「Unicode」指的是带有 BOM 的小端序 UTF-16。[2]
所谓的「UTF-8」指的是带 BOM 的 UTF-8。[3]
[1] Windows 里说的「ANSI」其实是 Windows code pages,这个模式根据当前 locale 选定具体的编码,比如简中 locale 下是 GBK。把自己这些 code page 称作「ANSI」是 Windows 的臭毛病。在 ASCII 范围内它们应该是和 ASCII 一致的。
[2] 把带有 BOM 的小端序 UTF-16 称作「Unicode」也是 Windows 的臭毛病。Windows 从 Windows 2000 开始就已经支持 surrogate pair 了,所以已经是 UTF-16 了,「UCS-2」这个说法已经不合适了。UCS-2 只能编码 BMP 范围内的字符,从 1996 年起就在 Unicode/ISO 标准中被 UTF-16 取代了(UTF-16 通过蛋疼的 surrogate pair 来编码超出 BMP 的字符)。都十多年了,求求大家别再误称了……
[3] 把带 BOM 的 UTF-8 称作「UTF-8」又是 Windows 的臭毛病。如果忽略 BOM,那么在 ASCII 范围内与 ASCII 一致。另请参见:「带 BOM 的 UTF-8」和「无 BOM 的 UTF-8」有什么区别?
作者:梁海
链接:https://www.zhihu.com/question/20650946/answer/15745831
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

这么说ANSI编码在我的机子里就是GBK,那一切都说的通了~~

后来我又注意到一个细节
我右击鼠标新建一个文本文档,使用Notepad++打开后,它是ANSI编码的
这里写图片描述

而我在Notepad++,这个不知道叫做什么栏
这里写图片描述
的“文件-新建”,它是UTF-8编码
这里写图片描述

于是今天解决了这个编码问题,还完成了另外两个上次遗留的问题:
①两个不同的创建文件方式有什么区别?
②ANSI编码可以通过编译,UTF-8不能通过,为什么?
编码&注释的小问题(未完成)

总结:我机子的操作系统默认GBK

0 0
原创粉丝点击