IO流、字符流、编码表、字符串(编码解码)、字符流的编码解码、字符流读写数据的方法(附复制java文件案例)、FileReader&FileWriter、字符缓冲流特有功能
目录
字符流概述
字符流=字节流+编码表
一个汉字存储:
如果是GBK编码,占2个字节
如果是UTF-8编码,占3个字节
并且编码全部是以负数开头和结尾
编码表概述
基础知识:
- 计算机中存储的信息都是用二进制数表示的;我们在屏幕上看到的英文、汉字等字符是二进制数转换之后的结果
- 按照某种规则将字符存储到计算机中被称之为编码。反之,将存储在计算机中的二进制数按照某种规则解析显示出来被成为解码
字符编码:就是一套自然语言的字符与二进制数之间的对应规则(A,65)
字符集
- 是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等
常见的字符编码有ASCII字符集、GBXXX字符集、Unicode字符集等
GBK:
最常用的中文码表。是GB2312标准基础上的扩展规范,使用了双字节编码方案,供收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等
Unicode:
- 为表达任意语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码。有三种编码方案,UTF-8、UTF-16和UTF32,最常用的是UTF-8编码
- UTF-8编码:可以用来表示Unicode标准种任意字符。互联网工程小组(IETF)要求所有互联网协议都必须支持UTF-8编码。它使用一至四个字节为每个字符编码
编码规则
128个IS-ASCII字符,只需要一个字节编码
拉丁文等字符,需要二个字节编码
大部分常用字(含中文),使用三个字节编码
其他极少使用的Unicode辅助字符,使用四字节编码
小结:采用何种规则编码,就要采用何种规则解码,否则就会出现乱码的情况
字符串的编码解码(String类中的方法)
编码:
方法名 | 作用 |
---|---|
byte[] getBytes() | 使用平台的默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中 |
byte[] getBytes(String charsetName) | 使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中 |
代码示例:
String s = "中国";
byte[] by = s.getBytes();
System.out.print(Arrays.toString(by)); //[-28, -72, -83, -27, -101, -67]
解码:
方法名 | 作用 |
---|---|
String(byte[] bytes) | 通过使用平台默认字符集解码指定的字节数组来构造新的String |
String(byte[] bytes,String charsetName) | 通过指定的字符集解码指定的字节数组来构造新的String |
代码示例:
byte[] by = {
-28, -72, -83, -27, -101, -67};
String s =new String(by);
System.out.print(s); //中国
字符流中的编码解码问题
字符抽象基类:
Reader:字符输入流的抽象类
Writer:字符输出流的抽象类
字符流中的编码解码问题相关的两个实现类
InputStreamReader
所在包:java.io
public class InputStreamReader
extends Reader
注意:字符流写入数据时并不会直接写入数据,在flush之前所写入的数据都早缓冲区内存放。
真正写入数据仍然靠字节流写入
InputStreamReader的两个常用构造方法
方法名 | 作用 |
---|---|
InputStreamReader(InputStream is) | 默认字符集编码的构造方法 |
InputStreamReader(InputStream is,String charsetName) | 指定字符集编码的构造方法 |
OutputStreamWriter
所在包:java.io
public class OutputStreamWriter
extends Writer
注意:在输入输出字符流对象时write()或read()后要立即close()否则会造成文件写入方法出错
OutputStreamWriter的两个常用构造方法
方法名 | 作用 |
---|---|
OutputStreamWriter(OutputStream os) | 按照默认字符集构造方法 |
OutputStreamWriter(OutputStream os,String charsetName) | 按照指定字符集构造方法 |
字符流读写数据的方法
字符流写入数据的5种方法
方法名 | 作用 |
---|---|
void write(int c) | 写入一个字符 |
void write(char[] chf) | 写入一个字符数组 |
void write(char[] chf,int off,int len) | 写入字符数组的一部分 |
void write(String str) | 写入一个字符串 |
void write(String str,int off,int len) | 写入字符串的一部分 |
void flush() | 刷新流,刷新后才可以看到输入的数据,否则数据在缓冲区内等待刷新 |
void close() | 关闭流,在执行close时会先执行一次flush |
代码示例:
OutputStreamWriter out=new OutputStreamWriter(new FileOutputStream("写入文件名"));
//write(char ch);
char ch="a";
out.write(ch);
//write(char[] ch);
char[] ch={
"a","b","c"};
out.write(ch);
//write(char[] ch,int off,int len);
char[] ch={
"a","b","c","d","e"};
out.write(ch,1,3);
//write(String str);
out.write("abcde");
//write(String str,int off,int len);
out.write("abcdef",1,4);
out.close(); //注意,在系统调用close()之前会自动调用一次flush()方法
字符流读取数据的两种方法
方法名 | 作用 |
---|---|
int read() | 一次读取一个数据 |
int read(char[] chf) | 一次读取一个字符数组,并将读取的数据传入字符数组中 |
代码示例:
InputStreamReader() in=new InputStreamReader(new FileInputStream("读取文件名"));
//int read();
char ch;
while( (ch = in.read() ) != -1){
//将字符的值转换为int赋值给ch
System.out.print((char)ch);
}
//int read(char[] cbuf);
char[] ch;
while( (len = in.read(ch)) ){
//将字符流的值赋值给字符数组,返回字符数组实际长度
System.out.print( new String(ch) );
//调用String构造方法将字符数组转换为字符串
}
复制java文件小案例
思路:
1.根据数据源创建字符输入流对象 reader
2.根据目的地创建字符输出流对象 writer
3.读写数据,复制文件
4.释放资源
代码示例:
OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream("目的地路径名"));
//目的地write
InputStreamReader in = new InputStreamReader(new FileInputStream("要复制的数据源"));
//数据源read
int len;
char[] chr = new char[1024];
while((len = in.read(chr)) != -1){
out.write(chr,0,1);
//write(char[] ch,int off,int len);方法写入字符数据
}
in.close();
out.close();
FileReader
所在包:java.io
public class FileWriter
extends OutputStreamWriter
FileReader
所在包:java.io
public class FileReader
extends InputStreamReader
案例:用FileWriter和FileReader复制java文件
代码示例:
FileWriter fw = new FileWriter("复制目的地");
FileReader fr = new FileReader("数据源");
int len;
char[] ch = new char[1024];
while( (len=fr.read(ch))!=-1 ){
fw.write(ch,0,len);
}
fw.close();
fr.close();
字符缓冲流(Buffered)
BufferedReader
所在包:java.io
public class BufferedReader
extends Reader
构造函数:BufferedReader(Reader in);
//FileReader fr = new FileReader();
//BufferedReader bfr = new BufferedReader(fr);
这两步可用内部类方式合并为:
BufferedReader bfr = new BufferedReader(new FileReader("文件名"));
BufferedWriter
所在包:java.io
public class BufferedWriter
extends Writer
构造函数:BufferedWriter(Writer out);
字符缓冲流的特有功能
BufferedWriter:
- void newLine():写一行行分隔符,行分隔符字符串由系统属性定义 代替:\n , \r\n , \r
BufferedReader:
- String readLine():读一行文字,结果返回包含行的内容的字符串,不包含任何终止字符,如果结尾已经到达,则为null
代码示例:
BufferedWriter bfw = new BufferedWriter(new FileWriter("目标文件"));
BufferedReader bfr = new BufferedReader(new FileReader("数据源"));
for(int i=0;i<10;i++){
bfw.write("hello"+i);
bfw.newLine();
//代替bfw.write("\r\n");
bfw.flush();
//每输入一个数据就刷新一下
}
String str;
while( (str=readLine)!=null ){
System.out.println(str);
//注意:readLine()方法无法检测到换行终止字符,所以如果需要显示换行输出必须手动添加换行符"println"
}
bfw.close();
bfr.close();
案例:复制java文件(字符缓冲流特有功能改进版)
思路:
1.根据数据源创建缓冲字符流输入对象
2.根据目的地创建字符缓冲输出流对象
3.读写数据,复制文件:使用字符缓冲流特有功能(readLine())实现
4.释放资源
代码示例:
BufferedWriter bfw = new BufferedWriter(new FileWriter("目的地"));
BufferedReader bfr = new BufferedReader(new FileReader("数据源"));
String str;
while((str = bfr.readLine())!=null){
bfw.write(str);
bfw.newLine();
bfw.flush();
}
bfw.close();
bfr.close();