编码集的问题
在传输中文文本文件的时候,字节流显然不如字符流有优势,会出现乱码问题,这主要是在编码汉字的时候出现了问题。
当直接通过windows自带的记事本.txt文件编写汉字的时候,默认存储编码格式是ANSI,即中文状态下的GBK,而我们开发常用的是utf-8编码集,所以在读取或者写入的时候会出现问题,一般的解决办法就是更改记事本的编码存储格式,另存为修改即可,还有就是通过转换流解决。
编码集的分类
- GB2312:中国简体文字和一部分少数民族的文字(1995年)
- GBK(ANSI在中文状态下指的是GBK): windows操作系统,默认的中文模式的编码集,新国标,包含所有的简体文字和少数民族文字(GB2312升级版)
- GB18030 :GBK的升级版本
- BIG5:中文繁体字的编码,台湾地区使用
- UTF-8 :万国码,开发中统一使用的编码集,中文占位3字符,其他占位1个字符
- UTF-16(unicode): 所有字符都是2个字节,对于英文和数字浪费空间,但是对世界各国语言的包容性最大
- ASCII :最简单的编码集128个
记事本的BOM头问题
BOM(Byte Order Mark)微软记事本独有标识,字节序列标记,用来标识文件的编码类型。只有utf-8和unicode会出现这个问题,明面无法查看,需要通过EditPlus,使用十六进制打开才能看到,出现在编码的开头位置。
注意事项
(1)utf-8的BOM头是 EF BB BF
(2)unicode 的BOM头是 FF FE ,末尾的 FE比 FF小,属于小端
(3)unicode big endian 的 BOM头是 FE FF 属于大端
(4)如果文本内容是由程序写入的,则没有BOM头
(5)BOM头可能导致XML文件解析出现问题,且问题不可见
转换流
字节转字符输入流:InputStreamReader
该类流是字符输入流FileReader的父类,将字节输入流转换为字符输入流,获取硬盘上的字节,根据编码转为字符读取到内存
//代码演示
public class Demo4 {
public static void main(String[] args) throws IOException {
//创建字节输入流,获取硬盘的字节
FileInputStream fis = new FileInputStream("D:\\Java\\md2.txt");
//创建转换流,将字节流导入,并确定编码格式
InputStreamReader isr = new InputStreamReader(fis, "GBK");
//和FileReader一样,字符读取
int len = -1;
char[] buffer = new char[1024 * 4];
while ((len = isr.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, len));
}
//字节流已经被包装到转换通道中,所以只需要关闭外层即可
isr.close();
}
}
字符转字节输出流:OutputStreamWriter
该类流是字符输出流FileWriter的父类,将内存中的字符转成字节保存到硬盘中,使用方式与InputStreamWriter一样,最后的方法也于FileWriter一样。
系统缓冲流
一种缓冲机制,将读取的数据临时保存到一个缓冲区间,区间填满后再写入或输出。
(1)减少对硬盘的操作次数,程序运行效率会提高
(2)有效保护硬盘
(3)自带缓冲区,默认是8KB,可以通过构造方法自己设置大小
字节缓冲流
- 构造方法
//字节缓冲输入流
BufferedInputStream(InputStream in);
BufferedInputStream(InputStream in, int size);
//字节缓冲输出流
BufferedOutputStream(OutputStream out);
BufferedOutputStream(OutputStream out, int size);
- 方法流程
- 找到源文件
- 判断
- 确定目标文件(拷贝使用)
- 准备输入缓冲和输出缓冲流对象
- 准备缓冲区,读取数据,写入数据
- 关闭资源,先开后关,只关缓冲流
缓冲流其实就是【装饰者设计模式】,其使用方法同一般的输入输出流类似,只不过其构造器需要将节点流类对象导入,实现功能处理。
//字节缓冲流拷贝文件的代码演示:
public class Demo1 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("D:\\Java\\流.png");
FileOutputStream fos = new FileOutputStream("D:\\Java\\流3.png");
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int len = -1;
byte[] buffer = new byte[1024 * 8];
while ((len = bis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
bos.flush();
}
bos.close();
bis.close();
}
}
字符缓冲流
字符缓冲流默认的缓冲区是一个char类型的数组,元素格式为8192(8个字节大小)。
构造方法
//字符缓冲输入流
BufferedReader(Reader in);
BufferedReader(Reader in, int sz);
//字符换缓冲输出流
BufferedWriter(Writer out);
BufferedWriter(Writer out, int sz);
普通方法流程同字节流,字符缓冲流提供了两种新的常用读写方法:
- 一种是可以直接读取一行的方法 readLine(),返回结果为字符串
- 一种是用于写入的换行方法 newLine()
- 【转换流】的结果也可以被装饰到缓冲流中,以实现这两种方法
//读取
public class Demo5 {
public static void main(String[] args) throws IOException {
//匿名调用形式,将文件输入流转为字符流,然后导入字符缓冲流
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream("D:/Java/Blog/Demo.txt"), "GBK"));
String str = null;
while ((str = br.readLine()) != null) {
System.out.println(str);
}
br.close();
}
}
//写入
public class Demo5 {
public static void main(String[] args) throws IOException {
//匿名调用形式
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream("D:/Java/Blog/Demo.txt", true), "GBK"));
bw.newLine(); //换行
bw.write("宝剑埋冤狱,忠魂绕白云————胡宗宪");
bw.flush();
bw.close();
}
}