FileOutputStream fileOutputStream =
new FileOutputStream("module-11\\data\\out.txt");
fileOutputStream.write(100);
fileOutputStream.write(35);
FileInputStream fileInputStream =
new FileInputStream("module-11\\data\\out.txt");
System.out.println(fileInputStream.read());// 100
System.out.println(fileInputStream.read());// 35
先创建了一个out.txt的文件,写入两个字节的内容。因为文件最基本的格式就是01二进制的样子,所以这个out.txt,里面存放的就是100和35的二进制数据。用 binary viewer打开
用binaryViewer打开out.txt,查看里面的二进制数据。可以看到:
64 是16进制数,占一个字节,转化二进制:01100100 刚好是100,
23 是16进制数,占一个字节,转化二进制:00100011 刚好是 35,
这也验证了我刚刚确实在out.txt里存入的100和35是按二进制存储的。
常说的 用UTF-8,GBK编码 打开文件(注意是打开文件)是什么意思呢?他们只是读取这基本的二进制数据,不会去改变数据本身。他们根据自己的编码规则,会去读取字节数据,然后把他转化为字符。在这里ASCII编码,就读取了01100100,然后根据ASCII的编码,这个二进制对应的字符就是d,同理,00100011对应字符#。
打开文本文件,肯定是要选编码格式,编码格式不同,打开得到的字符有时候就不同
但是 我们无论以什么编码打开out.txt源文件,得到的二进制数据肯定还是我们刚刚存入的01100100,00100011
FileInputStream fileInputStream =
new FileInputStream("module-11\\data\\out.txt");
System.out.println(fileInputStream.read());//100
System.out.println(fileInputStream.read());//35
我们重新读取文件 可以看到,数据源并没有发生改变
反过来,我们创建一个txt文件,然后写入 汉字 “中”,我们保存的时候,可以选择不同的编码保存(注意这里是保存文件),编码不同,保存的文件结果,基本也不同(这里的文件结果不同,指的是文件的二进制数据不同),所以这就形成了我们常见的 乱码(用A 编码保存文件,以B编码打开文件)。所以我们保存文件,是用什么编码,那么打开文件一定也要是对应的编码格式打开,否则就形成乱码。
关于Unicode和GBK,UTF-8,UTF-16的关系解释:
Unicode是用来存储全世界的语言的一张映射表,全世界所有的字符都被Unicode编码,GBK,UTF-8,UTF-16是Unicode的实现方式之一。
看看UTF-8的编码方式,(UTF-8是对Unicode进行编码,举个例子: 人 这个字符如果保存为Utf-8格式的文件,软件编码的顺序为 人 -> Unicode编码->UTF-8编码 ),中间这道编码有唯一性,因为这个是 全世界统一的编码规范,为什么要有这 Unicode编码->UTF-8编码 这道编码顺序呢,为什么有个全世界统一的编码规范,而还要去扩展编码规范呢?这个下一篇文章再说!
找了两个Unicode字符,但是好像在很多地方都不支持,表现出复制后为乱码(这里要特别注意,这两个字符虽然是乱码,只是因为软件不支持这两个Unicode 的图像化),分别以UTF-8格式 保存在文本里。
-
𐆙 U+10199
-
𐆘 U+10198
就这样复制了以UTF-8 另存 就行了,然后然后查看二进制文件。
-
这两个字符只是软件不支持图像化,但是编码依然是UTF-8 的编码,见下图。
假设我们在一个window桌面建立一个 .txt 文件,然后在里面写入文件,这个时候可以保存文件为任意的格式,根据格式的不同,这个文件的二进制的数据也不同,因为编码都是有一定的规则。我们可以想象每一个写入的 字符 都是 U+????? (Unicode码点),然后就是根据不同的编码方式,把这些 字符转化为01二进制的计算机存储的数据。这个是好理解的。
但是在java里面这个就难理解了,首先在 java内部(这个内部指的是在JVM里面)是用的UTF—16这种编码格式,比如说一个特殊的字符串
"a我𝕆"
字符转换为UTF—16 格式,在这里就是 \u0061\u6211\uD835\uDD46
(\u0061代表这个是一个UTF—16 码元 ),每个 char 都只能存储这一个\u0061 码元,因为这是0x0061(16进制数)有2个字节,在java里char类型是占两个字节。𝕆 字符比较特别,2个 UTF—16 码点 才能表示他,所以这个字符要2个char来存储,所以这整个 "a我𝕆"
的string的长度为4 ,因为他用了4个 char 存放(但是好像是jdk1.8 后 String类 就不是用 char[] 来存放数据,而是用 byte[] 来做为存储的容器。我们这里还是假设用char[] 来做String的容器,其实用 byte[] 来做容器了,你也可以把它内部当作char[])
插入一条例子
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
new FileOutputStream("module-11\\data\\UTF_8.txt"), StandardCharsets.UTF_8);
//其实默认的就是UTF-8编码 格式写入文件
String s = "\u0061\u6211\uD835\uDD46"; // a我𝕆
char[] chars = s.toCharArray();
System.out.println(chars.length);//4
outputStreamWriter.write(chars[3]);
outputStreamWriter.write(chars[2]);
outputStreamWriter.write(chars[1]);
outputStreamWriter.write(chars[0]);
outputStreamWriter.flush();
// 存储的结果: ??我a
第二次顺序存储:
// System.out.println(chars.length);//4
// outputStreamWriter.write(chars[0]);
// outputStreamWriter.write(chars[1]);
// outputStreamWriter.write(chars[2]);
// outputStreamWriter.write(chars[3]);
// outputStreamWriter.flush();
// // 存储的结果: a我𝕆
write方法 只能每次读入一个 char ,在这里所有的文本在被读入后,会被 重新进行一次转化,就是UTF—16 到 Unicode的转化,这里只能这样理解,才能解释这里两次存储的差异性。
读文件就是反过来,
可以看到二进制的数据,当编码确定就可以直接转化为字符,这里的3个字节,是UTF-8的编码规则
byte[] bytes1 = new byte[3];
bytes1[0] = (byte) 0b11100110;
bytes1[1] = (byte) 0b10001000;
bytes1[2] = (byte) 0b10010001;
String s = new String(bytes1, StandardCharsets.UTF_8);
System.out.println("s = " + s);// s = 我
FileOutputStream fileOutputStream = new FileOutputStream("byte.txt");
fileOutputStream.write(bytes1);
fileOutputStream.flush();//存储的结果也是 “我”
第一次写csdn,不太会,希望能多多包涵,也希望能提点意见