// Reader/Write概述:
// inputStream和OutputStream类处理的是字节流,也就是数据最小单元是一个字节,它包括8个二进制位,
// 很多时候都要在文件中存放采用特定字符编码的字符,为了便于读取采用各种字符编码的字符,java.io包中提供
// 了Reader/Writer类,他们分别表示字符输入流和字符输出流
// 在处理字符流时,最重要的问题是进行字符编码的转换,java采用Unicode字符编码,对于每一个字符,java虚拟机
// inputStream和OutputStream类处理的是字节流,也就是数据最小单元是一个字节,它包括8个二进制位,
// 很多时候都要在文件中存放采用特定字符编码的字符,为了便于读取采用各种字符编码的字符,java.io包中提供
// 了Reader/Writer类,他们分别表示字符输入流和字符输出流
// 在处理字符流时,最重要的问题是进行字符编码的转换,java采用Unicode字符编码,对于每一个字符,java虚拟机
// 会为其分配两个字节的内存,而在文本文件中,字符有可能采用其他类型的编码,比如GBK和UTF-8字符编码等,以下演示了字符"好"的各种字符编码
public class Test18 {
private static void readBuff(byte[] buff) throws IOException{
ByteArrayInputStream in = new ByteArrayInputStream(buff);
int data;
while((data = in.read())!=-1){
System.out.println(data);
}
System.out.println();
in.close();
}
// 对于以上字符类型的变量c,java虚拟机为它在内存中分配了两个字节,用来存放字符"好"的Unicode字符编码,"好"的Unicode字符编码为89和125,对应的二进制
// 序列为:01011001 01111101,对于String类型的变量s,由于它仅仅包含一个字符"好",java虚拟机也为它在内存中分配两个字节,用来存放字符"好"的Unicode字符编码
// String的getBytes(String encode)方法返回特定类型的编码,不带参数的话getBytes()方法则使用本地操作系统的默认字符编码,有两种方式获得本地平台的字符编码类型
// 依次是:
public static void main(String[] args) throws IOException {
System.out.println("内存中采用Unicode编码");
char c = '好';
int lowBit = c & 0xFF;
int highBit = (c & 0xFF00) >>8;
System.out.println(highBit + " " + lowBit);
String s = "好";
System.out.println("采用本地操作系统的默认字符编码");
readBuff(s.getBytes());
System.out.println("采用GBK字符编码");
readBuff(s.getBytes("GBK"));
System.out.println("采用标准UTF-8字符编码");
readBuff(s.getBytes("UTF-8"));
System.out.println(System.getProperty("file.encoding"));//在中文操作系统中打印GBK
System.out.println(Charset.defaultCharset());//如果操作系统为中文操作系统,以上一般打印"GBK",Charset类位于java.nio.charset包中
// Reader类能够将输入流中采用其他编码类型的字符转换为Unicode,然后为Unicode字符分配内存,Write类能够把内存中的Unicode字符转换为其他编码类型的字符,再写到输出流中
// 默认 Reader和Writer会在本地平台的字符编码和Unicode字符转码之间进行编码转换
// 如果要输入和输出采用特定类型编码的字符串,可以使用InputStreamReader类和OutputStreamWriter类,在他们的构造方法中,可以指定输入流或输出流的字符编码
// 在为字符分配内存时,java虚拟机对字符统一采用Unicode字符编码,因此java程序处理字符具有平台独立性。
// Reader类的子类及其间接子类:
// 子类:CharArrayReader字符数组输入流,从内存中的字符数组中读取字符,因此他的数据源是一个字符数组,构造方法CharArrayReader(char[] buf,int offset,int length),read()方法每次读取一个字符
// StringReader字符串输入流,StringReader(String s)指定字符串类型的数据源
// InputStreamReader类,InputStreamReader(InputStream in,String charsetName),按照参数charsetName指定的字符编码读取输入流中的字符。
// 例如:InputStreamReader reader = new InputStreamReader(new FileInputStream("D:\\test.txt"),"UTF-8");
// char c = (char)reader.read();
// 以上代码表示指定输入流的字符编码为UTF-8,InputStreamReader的read()方法从输入流中读取一个UTF-8字符,再把它转换成Unicode字符,此时
// 变量c为Unicode字符,在内存中占用两个字节,比如现在读取的字符是"好",read()的执行步骤如下:
// 从输入流中读取3个字节:229,165,189,这三个字节代表字符"好"的UTF-8字符编码,接着计算出字符"好"的Unicode字符编码为89和125
// 最后为"好"分配两个字节的内存空间,这两个字节的取值分别为89和125,为了提高操作的效率,可以用BufferedReader来装饰InputStreamReader
// FileReader类是InputStreamReader的一个子类,用于从文件中读取字符数据,该类只能按照本地平台的字符编码来读取数据,用户不能指定其他字符编码类型
// FileReader(File file),FileReader(String name) 构造方法前者是File类,后者是一条路径
// BufferedReader装饰流,BufferedReader(Reader in)参数in指定被装饰的Reader类,BufferedReader(Reader in,int sz)参数in
// 指定被装饰的Reader类,参数sz指定缓冲区的大小,以字符为单位。
// Write类的子类及其间接子类:
// 子类:字符数组输出流 CharArrayWrite类,CharArrayWrite类的write(char c)方法向字符输出流写入一个字符,他的toCharArray()方法返回包含所有输出数据的字符数组
// OutputStreamWriter类,OutputStreamWriter(OutputStream out,String charsetName),按照参数charsetName指定的字符编码向输出流写入字符
// OutputStreamWrite writer = new OutputStreamWriter(new FileOutputStream("D:\\test.txt"),"UTF-8");
// char c = "好";
// writer.writer(c);
// 以上表示:对于每一个写到test.txt文件中的字符,都会把它转换为UTF-8字符编码,writer.write(c)方法时,OutputStreamWriter的write()方法执行以下步骤:
// 变量c取值两个字节,分别为89和125,他们代表"好"的Unicode字符编码,接着字符"好"的UTF-8字符编码为229,165,189,最后向输出流写入这三个字节。
// 为了提高效率还是可以使用BufferedWriter,将OutputStream包装在BufferedWriter里面,然后再把BufferedWriter包装在PrintWriter中
// FileUtil提供了以下两个实用方法:
// readFile(String fileName, String charsetName)从一个文件中逐行读取字符串,并将它们打印到控制台,charsetName参数指定文件的字符编码
// copyFile(String from,String charsetFrom,String to,String charsetTo):把源文件中的字符内容拷贝到目标文件中,并且会执行相关的字符编码转换,参数from指定
// 源文件的路径,参数charsetFrom指定源文件的字符编码,参数to指定目标文件的路径,参数charsetTo指定目标文件的字符编码,如果参数charsetFrom为null,则表示源文件采用本地平台的字符编码
// FileWriter类是OutputStreamWriter的一个子类,用于向文件中写字符,该类只能按照本地平台的字符编码来写数据,用户不能指定其他字符编码类型,FileWriter类的构造方法,FileWriter(File file),FileWriter(String name)
// BufferedWriter装饰流,BufferedReader有一个readLine()方法,而BufferedWriter没有相应的writeLine()方法,如果要输出一行字符串,应该再用PrintWriter来装饰BufferedWriter,PrintWriter的println(String s)
// 方法可以输出一行字符串,BufferedWriter的构造方法,BufferedWriter(Writer out,int sz),sz表示缓冲区大小,out指定了被装饰的Writer类
// PrintWriter和printStream一样也能输出格式化的数据,两者的写数据方法很相似,例如print(int i),print(long l),println(String s)
// 1.每个print方法都有一个println方法对应,printWriter的所有print和println方法都会抛出IOException,客户程序可以通过PrintWriter的checkError()方法来判断写数据是否成功,如果返回true表示遇到了错误
// 3.printWriter和BufferedWriter都带有缓冲区,区别在于后者只有在缓冲区满的时候才会执行写数据的操作,而前者可以让用户来决定缓冲区的行为,默认下,PrintWriter也只有缓冲区满的时候才会执行物理写数据,但是PrintWriter
// 的一些构造方法有一个autoFlush阐述,当参数为true表示printWriter执行println方法会自动把缓冲区的数据写入输出流,PrintWriter不仅能装饰Writer,还能把OutputStream转换为Writer
// PrintWriter(Writer writer,boolean autoFlush)
// PrintWriter(OutputStream out,boolean autoFlush)
// PrintWriter和PrintStream的println(String s)方法都能写字符串,两者的区别在于,后者只能写本地平台的字符编码,而前者使用的字符编码取决于被装饰的Writer类所有的字符编码,在输出字符数据场合,应该优先考虑PrintWriter
}
}