1.1 转换流出现的原因
1.1.1 字节流读数据可能出现问题
字节流一次读取一个字节的方式读取带有汉字的文件是有问题的,因为你读取到一个字节后就转为字符在控制台输出了,而汉字是由2个字节组成的,所以这里会出问题。
文件复制的时候,字节流读取一个字节,写入一个字节,这个没有出现问题,是因为最终底层会根据字节做拼接,得到汉字。
- 汉字存储的规则:
- 左边的字节数据肯定是负数,
- 右边的字节数据可能是负数,也可能是正数,大部分情况下是负数。
1.1.2 案例代码
public class FileInputStreamDemo {
public static void main(String[] args) throws IOException {
//基本字节流一次读取一个字节
// FileInputStream fis = new FileInputStream("a.txt");
//
// int by;
// while((by=fis.read())!=-1) {
// System.out.print((char)by);
// }
//
// fis.close();
//String s = "hello";
//[104, 101, 108, 108, 111]
String s = "你好";
//[-60, -29, -70, -61]
byte[] bys = s.getBytes();
System.out.println(Arrays.toString(bys));
}
}
1.1.3 转换流的组成部分
转换流 = 字节流 + 编码表
这句话怎么理解 ? 往下看, 先说编码表
1.2 编码表概述和常见编码表
1.2.1 什么是编码表?
- 编码表:
- 由字符及其对应的数据组成的一张表
- ASCII:
- ‘a’ 97
- ‘A’ 65
- ‘0’ 48
- 常见的编码表:
- ASCII : 美国标准信息交换码, 用一个字节的7位表示数据
- ISO-8859-1 : 欧洲码表, 用一个字节的8位表示数据, 兼容ASCII
- GB2312 : 中文码表的升级版, 融合了更多的中文文字符号, 兼容ASCII
- UTF-8 : 是一种可变长度的字符编码, 用1-3个字节表示数据, 又称为万国码, - 兼容ASCII
- 用在网页上可以统一页面中的中文简体繁体和其他语言的显示.
1.2.2 乱码问题
针对同一个数据, 采用的编码和解码不一致导致

1.3 String类中的编码和解码问题
1.3.1 方法摘要&编码和解码
-
编码
- 把看得懂的变成看不懂的
- public byte[] getBytes(String charsetName) throws UnsupportedEncodingException
- 使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
- 把看得懂的变成看不懂的
-
解码
- 把看不懂的变成看得懂的
- public String(byte[] bytes, String charsetName)
- 通过使用指定的 charset解码指定的 byte 数组,构造一个新的 String。
重点强调 : 编码和解码的方式需要一致
- 把看不懂的变成看得懂的
1.3.2 案例代码
public class StringDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
//定义一个字符串
String s = "你好";
//编码
//byte[] bys = s.getBytes();//使用平台的默认字符集将此 String 编码为 byte 序列
//默认编码是GBK
//[-60, -29, -70, -61]
//byte[] bys = s.getBytes("GBK"); //指定编码GBK
//[-60, -29, -70, -61]
byte[] bys = s.getBytes("UTF-8"); //指定编码UTF-8
//[-28, -67, -96, -27, -91, -67]
System.out.println(Arrays.toString(bys));
//解码
//String ss = new String(bys); //通过使用平台的默认字符集解码指定的 byte 数组
// String ss = new String(bys,"GBK");//指定编码GBK
String ss = new String(bys,"UTF-8");//指定编码UTF-8
System.out.println(ss);
}
}
1.4 转换流中的编码和解码问题
1.4.1 转换流指的是?
转换流其实就是一个字符流。
转换流 = 字节流 + 编码表
1.4.2 转换流的构造方法
-
OutputStreamWriter 字符输出流
- public OutputStreamWriter(OutputStream out)
- 根据默认编码把字节流的数据转换为字符流
- public OutputStreamWriter(OutputStream out,String charsetName)
- 根据指定编码把字节流数据转换为字符流
- public OutputStreamWriter(OutputStream out)
-
InputStreamReader 字符输入流
- public InputStreamReader(InputStream in)
- 用默认的编码读数据
- public InputStreamReader(InputStream in,String charsetName)
- public InputStreamReader(InputStream in)
1.4.3 案例代码
public class ConversionStreamDemo {
public static void main(String[] args) throws IOException {
//public OutputStreamWriter(OutputStream out):默认编码GBK
//OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"));
//public OutputStreamWriter(OutputStream out,String charsetName)
//OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"),"GBK");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"),"UTF-8");
//调用写数据的方法
osw.write("你好");
//释放资源
osw.close();
System.out.println("------------------------");
//public InputStreamReader(InputStream in):默认编码GBK
//InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"));
//public InputStreamReader(InputStream in,String charsetName)
//InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"),"GBK");
InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"),"UTF-8");
//读数据:一次读取一个字符数据
int ch;
while((ch=isr.read())!=-1) {
System.out.print((char)ch);
}
//释放资源
isr.close();
}
}
1.5 OutputStreamWriter写数据的5种方式
1.5.1 方法摘要
* OutputStreamWriter写数据方法
* public void write(int c):写一个字符
* public void write(char[] cbuf):写一个字符数组
* public void write(char[] cbuf,int off,int len):写一个字符数组的一部分
* public void write(String str):写一个字符串
* public void write(String str,int off,int len):写一个字符串的一部分
1.5.2 案例代码
public class OutputStreamWriterDemo {
public static void main(String[] args) throws IOException {
//创建字符输出流对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"));
//public void write(int c):写一个字符
// osw.write(97);
// osw.write('a');
//写完数据后,没有发现数据,为什么呢?
//1字符=2字节
//文件中的数据存储的基本单位是字节
//public void write(char[] cbuf):写一个字符数组
// char[] chs = {'a','b','c','d','e'};
// osw.write(chs);
//public void write(char[] cbuf,int off,int len):写一个字符数组的一部分
// char[] chs = {'a','b','c','d','e'};
// osw.write(chs, 1, 3);
//public void write(String str):写一个字符串
// osw.write("hello");
//public void write(String str,int off,int len):写一个字符串的一部分
osw.write("hello", 0, 3);
// //void flush():刷新该流的缓冲
// osw.flush();
//
// //释放资源
osw.close(); //关闭此流,但要先刷新它
}
}
1.6 InputStreamReader读数据的2种方式
1.6.1 方法摘要
* public int read():一次读取一个字符
* public int read(char[] cbuf):一次读取一个字符数组
1.6.2 案例代码
public class InputStreamReaderDemo {
public static void main(String[] args) throws IOException {
//创建字符输入流对象
// InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));
InputStreamReader isr = new InputStreamReader(new FileInputStream("OutputStreamWriterDemo.java"));
//public int read():一次读取一个字符
// int ch;
// while((ch=isr.read())!=-1) {
// System.out.print((char)ch);
// }
//public int read(char[] cbuf):一次读取一个字符数组
char[] chs = new char[1024];
int len;
while((len=isr.read(chs))!=-1) {
System.out.print(new String(chs,0,len));
}
//释放资源
isr.close();
}
}
网友评论