为什么会出现字符流?
由于字节流操作中文不是特别的方便,所以Java就提供字符流
字符流 = 字节流 + 编码表
用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接成中文,如何识别是中文的呢?
汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数
什么是字符集?
是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等,计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBXXX字符集、Unicode字符集等
ASCII字符集:
ASCII:是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)基本的ASCII字符集,使用7位表示一个字符共128字符。ASCII的扩展字符集使用8位表示一个字符,共256字符,方便支持欧洲常用字符。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等
GBXXX字符集:
GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等
Unicode字符集:
UTF-8编码:可以用来表示Unicode标准中任意字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。它使用一至四个字节为每个字符编码
编码规则:
128个US-ASCII字符,只需一个字节编码
拉丁文等字符,需要二个字节编码
大部分常用字(含中文),使用三个字节编码
其他极少使用的Unicode辅助字符,使用四字节编码
测试不同字字符集下"中国"两个字的编码
public static void main(String[] args) throws Exception { //定义一个字符串 String s = "中国"; byte[] a = s.getBytes(); //[-28, -72, -83, -27, -101, -67] byte[] UTF8 = s.getBytes("UTF-8"); //[-28, -72, -83, -27, -101, -67] byte[] GBK = s.getBytes("GBK"); //[-42, -48, -71, -6] System.out.println(Arrays.toString(a)); System.out.println(Arrays.toString(UTF8)); System.out.println(Arrays.toString(GBK)); String s1 = new String(a); String s2 = new String(UTF8,"UTF-8"); String s3 = new String(GBK,"GBK"); System.out.println(s1); System.out.println(s2); System.out.println(s3); }
输出:
[-28, -72, -83, -27, -101, -67] [-28, -72, -83, -27, -101, -67] [-42, -48, -71, -6] 中国 中国 中国
InputStreamReader:是从字节流到字符流的桥梁,它读取字节,并使用指定的编码将其解码为字符,它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
OutputStreamWriter:是从字符流到字节流的桥梁,使用指定的编码将写入的字符编码为字节,它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
字符流写数据的5种方式
void write(int c) 写一个字符
void write(char[] cbuf) 写入一个字符数组
void write(char[] cbuf, int off, int len) 写入字符数组的一部分
void write(String str) 写一个字符串
void write(String str, int off, int len) 写一个字符串的一部分
(注意,执行需要 flush() 刷新)
public static void main(String[] args) throws Exception{ OutputStreamWriter outputStreamWriter=new OutputStreamWriter(new FileOutputStream(".\\src\\hello.txt")); outputStreamWriter.write(97); //写一个字符 outputStreamWriter.flush(); char[] chs = {'a', 'b', 'c', 'd', 'e'}; outputStreamWriter.write(chs); //写一个字符数组 outputStreamWriter.flush(); outputStreamWriter.write(chs, 0, chs.length); //写字符数组的一部分 outputStreamWriter.write(chs, 1, 3); outputStreamWriter.flush(); outputStreamWriter.write("我是中国人"); //写一个字符串 outputStreamWriter.flush(); String s="我是中国人"; outputStreamWriter.write(s,1,s.length()-1); //写一个字符串的一部分 outputStreamWriter.flush(); outputStreamWriter.close(); }
字符流读数据的2种方式
int read() 一次读一个字符数据
int read(char[] cbuf) 一次读一个字符数组数据
public static void main(String[] args) throws Exception{ InputStreamReader inputStreamReader=new InputStreamReader(new FileInputStream(".\\src\\hello.txt")); int a; while((a=inputStreamReader.read())!=-1){ // 一次读取一个字符数据 System.out.print((char) a); } char[] b=new char[1024]; int len; while ((len=inputStreamReader.read(b))!=-1){ //一次读取一个字符数组
System.out.println(new String(b,0,len));
}
inputStreamReader.close();
}
字符流复制文件(InputStreamReader和OutputStreamWirter)
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(".\\src\\hello.txt")); OutputStreamWriter outputStreamWriter= new OutputStreamWriter(new FileOutputStream(".\\src\\helloCopy.txt")); char[] chs = new char[1024]; int len; while ((len = inputStreamReader.read(chs)) != -1) { outputStreamWriter.write(chs, 0, len); } outputStreamWriter.close(); inputStreamReader.close(); }
字符流复制文件(FileReader和FileWirter)
public static void main(String[] args) throws IOException { FileReader fileReader = new FileReader(".\\src\\hello.txt"); FileWriter fileWriter = new FileWriter(".\\src\\helloCopy.txt"); char[] chs = new char[1024]; int len; while ((len = fileReader.read(chs)) != -1) { fileWriter.write(chs, 0, len); } fileReader.close(); fileWriter.close(); }
总结:InputStreamReader 是用来读取原始字节流,可指定编码格式,而FileReader是读取字符流,使用系统默认的编码格式,当读取中文文件易出现乱码问题。
浙公网安备 33010602011771号