import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
public class Split4 {
public static void main(String args[]) throws IOException {
FileOutputStream fos = new FileOutputStream("d:/aa.txt");
fos.write(1);
fos.write(2);
fos.close();
FileReader fis = new FileReader("d:/aa.txt");
int a;
while((a = fis.read()) != -1){
System.out.println(a);
}
fis.close();
}
}
这个程序先是将两个整数1和2使用字符流写入到文件中,却使用字节流读出,能正确读出1,2。这是为什么呢?
public class FileReader extends InputStreamReader
用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要自己指定这些值,可以先在 FileInputStream 上构造一个 InputStreamReader。
很明显,这个类读取字符(2个字节)时候是根本地默认字符编码有关的,那么本地默认字符是什么呢?
System.out.println(Charset.defaultCharset());
输出为GBK,那么如何根据GBK读取呢,他是怎么区分这是2个数而不是将他们读成一个呢?查了一下资料,资料是这样说的:
首字节在81-FE 之间,尾字节在40-FE 之间 的字节被认为是汉字或者符号。16进制81的10进制表示为129,也就是第一个字节在129以上会被认为是汉字,那么我进行了这样的测试:(注意现在和Unicode还没有任何关系)
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
public class Split4 {
public static void main(String args[]) throws IOException {
FileOutputStream fos = new FileOutputStream("d:/aa.txt");
fos.write(129);
fos.write(2);
fos.close();
FileReader fis = new FileReader("d:/aa.txt");
int a;
while((a = fis.read()) != -1){
System.out.println(a);
}
fis.close();
}
}
这个程序只输出一个数字:65533 这个说明了FileReader read()的时候将文件中这两个字节看成是汉字了,一起读了出来,所以只有一行输出。
现在又出了一个新问题,那就是129和2用二进制表示为:10000001 00000010,并不是65533,我又进行了一些数据测试,将129改为130、150之类的,输出都是65533,这下用二进制表示不清了,这是为什么?难道是写入的时候出的问题,接着做了如下测试:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
public class Split4 {
public static void main(String args[]) throws IOException {
FileOutputStream fos = new FileOutputStream("d:/aa.txt");
fos.write(129);
fos.write(2);
fos.close();
// FileReader fis = new FileReader("d:/aa.txt");
FileInputStream fis = new FileInputStream("d:/aa.txt");
int a;
while((a = fis.read()) != -1){
System.out.println(a);
}
fis.close();
}
}
这个程序能正确输出129和2,证明了不是写入的时候的问题。那么就是在读取的时候,经过baidu我认为是GBK的问题,GBK遇到不认识的编码就都转化为'?'了,这就是为什么有的时候转码不对,会出现很多问号的情况,因为字符集它不认识啊。那么65533是GBK中问号的码吗?答案不太确定,因为后面的试验会证明,很可能是unicode码。
有没有可能通过字节流连续写入两个字节,使用字符流读出来一个汉字呢?我接着做了如下的试验。
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Tmp {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("d:/aa.txt");
fw.write("北京");
fw.close();
FileReader fis = new FileReader("d:/aa.txt");
//FileInputStream fis = new FileInputStream("d:/aa.txt");
int a;
while((a = fis.read()) != -1){
System.out.println(Integer.toBinaryString(a));
}
fis.close();
}
}
output:
101001100010111 //10进制为:21271
100111010101100 因此可以知道上面那个二进制数代表“北”字,下面的二进制数应该代表京字。按理说先后写入1010011 和00010111两个二进制码对应的int,那么使用FileReader读出来就应该是“北”字了。但是
System.out.println(Integer.parseInt("1010011", 2)); //这个二进制所表示的10进制是83,后面的二进制数表示的是23。
为什么第一个数没有129大呢,按理说汉字的第一个字节必须大于129啊,测试如下:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
public class Split4 {
public static void main(String args[]) throws IOException {
FileOutputStream fos = new FileOutputStream("d:/aa.txt");
fos.write(83);
fos.write(23);
fos.close();
FileReader fis = new FileReader("d:/aa.txt");
//FileInputStream fis = new FileInputStream("d:/aa.txt");
int a;
while((a = fis.read()) != -1){
System.out.println((char)a);
}
fis.close();
}
}
输出为S和方框符号,两行,这也印证了不大约129的第一个字节会被GBK认为1个字节就是一个字符。那么问题出在哪里,又做了如下调试:
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Tmp {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("d:/aa.txt");
fw.write("北京");
fw.close();
//FileReader fis = new FileReader("d:/aa.txt");
FileInputStream fis = new FileInputStream("d:/aa.txt");
int a;
while((a = fis.read()) != -1){
System.out.println(Integer.toBinaryString(a));
}
fis.close();
}
}
输出为:
10110001
10110001
10111110
10101001
这个程序是把北京两个字输出为4个字节,前两个字节是“北”字的组成部分。二进制换为10进制是两个177.这二个大于129,于是又做了如下测试:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
public class Split4 {
public static void main(String args[]) throws IOException {
FileOutputStream fos = new FileOutputStream("d:/aa.txt");
fos.write(177);
fos.write(177);
fos.close();
FileReader fis = new FileReader("d:/aa.txt");
//FileInputStream fis = new FileInputStream("d:/aa.txt");
int a;
while((a = fis.read()) != -1){
System.out.println((char)a);
}
fis.close();
}
}
输出:
北
这下匹配上了,通过写入两个字节,然后读出一个字符,顺利转化。那么,文件里存的应该是两个177的二进制连在一起啊,也就是1011000110110001
,这个二进制数表示的10进制数是45489,但是转化为int输出,为什么是21271呢,难道是转化的问题?百思不得其解,终于在“在线新华字典中”查到:
GBK十进制: | 45489 |
unicode十进制: | 21271 |
这下明了了,“北”字的GBK码为45489也就是文件中的二进制内容,而unicode码却是21271,看来是在输出的时候进行了GBK到unicode的转化
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Tmp {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("d:/aa.txt");
fw.write("北京");
fw.close();
FileReader fis = new FileReader("d:/aa.txt");
//FileInputStream fis = new FileInputStream("d:/aa.txt");
int a;
while((a = fis.read()) != -1){
System.out.println(a); //我觉得转化出现在这里
}
fis.close();
}
}
输出:
21271
20140
显然都是unicode码。今天先研究到这,记录下。