从流开始的IO世界生活(二)

一、字符流

为何会出现字符流

由于字节流操作中文不方便

  • 字符流=字节流+编码表

用字节流赋值文本文件时,文本文件也会有中文,但不会出现乱码问题,原因是最终底层操作会自动进行字节拼接成中文。

如何识别中文?

  • 汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package zi_fu_liu;

import java.io.IOException;
import java.util.Arrays;

public class Chinese {
public static void main(String[] args) throws IOException {
String a="你好";
byte[] b=a.getBytes("GBK");
byte[] c=a.getBytes("UTF-8");
System.out.println(Arrays.toString(b));//[-60, -29, -70, -61]
System.out.println(Arrays.toString(c));//[-28, -67, -96, -27, -91, -67]
}

}

汉字存储如果是GBK编码,占用两个字节;如果是UTF-8编码,占用3个字节

二、编码表

编码与解码

计算机中的信息都是用二进制表示的;我们在屏幕上看到的英文、汉字等字符是二进制数转换后的结果

编码:按照某种规则,将字符存储到计算机中,称为编码。

解码:将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码

注意:按照A编码存储,必须按照A编码解析,这样才能显示正确的文本符号。否则就会出现乱码

字符集

  • 一个系统支持的所有字符的集合,包括各国家的文字、标点符号、图形符号、数字等
  • 计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码
  • 常见的字符集有ASCLL字符集、GBXXX字符集、Unicode字符集等

Unicode字符集:

UTF-8编码:可以用来表示Unicode标准中任意字符,使用1-4个字节为每个字符编码

编码规则:

  • 128个US-ASCLL字符,只需要一个字节编码
  • 拉丁文等字符,需要两个字节编码
  • 大部分常用字(含中文),使用三个字节
  • 其他辅助字符,使用四个字节编码

三、字符串中的编码与解码

编码:

  • byte[] getBytes() :使用默认字符集将String编码为一系列字节,将结果存储到新的字节数组中
  • byte[] getBytes(String charsetName) : 使用特定字符集将其编码为一系列字节,将结果存入新的字节数组中

解码:

  • String(byte[] bytes):使用默认字符集解码指定字节数组来构造新的String
  • String(byte[] bytes,String charsetName): 通过指定的字符集解码指定的字节数组来构造新的String
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package zi_fu_liu;

import java.io.IOException;
import java.util.Arrays;

public class Chinese {
public static void main(String[] args) throws IOException {
String a="你好";
byte[] b=a.getBytes("GBK");
byte[] c=a.getBytes("UTF-8");
System.out.println(Arrays.toString(b));//[-60, -29, -70, -61]
System.out.println(Arrays.toString(c));//[-28, -67, -96, -27, -91, -67]
String a1=new String(b);
System.out.println(a1); //你好
String a2=new String(c);
System.out.println(a2); //浣犲ソ
String a3=new String(c,"UTF-8");
System.out.println(a3); //你好
}

}

四、字符流中的编码与解码

字符流抽象基类

  • Reader:字符输入流的抽象类
  • Writer:字符输出流的抽象类

字符流中和编码解码相关的两个类:

  • InputStreamReader
  • OutoutStreamWriter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package zi_fu_liu;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class zifuliu {
public static void main(String[] args) throws IOException{
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("zifuliu.txt"),"UTF-8");//浣犲ソ鍛�
osw.write("你好呀");
osw.close();
// InputStreamReader isr=new InputStreamReader(new FileInputStream("zifuliu.txt"),"GBK");//浣犲ソ鍛�
InputStreamReader isr=new InputStreamReader(new FileInputStream("zifuliu.txt"),"UTF-8");//你好呀
int len;
while((len=isr.read())!=-1){
System.out.print((char)len);
}
isr.close();

}

}

五、字符流写数据的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) 写一个字符串的一部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package zi_fu_liu;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

public class write_5 {
public static void main(String[] args) throws IOException{
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("zifuliu.txt"));
osw.write(97);//a
osw.write(99);//c

char[] ch={'a','b','c','d','e'};
osw.write(ch,1,4);//bcde

osw.write("hello!");//hello!
String a="myworld";
osw.write(a,0,a.length());//myworld

osw.close();
}

}
方法名 说明
flush() 刷新流,可以继续写数据
close() 关闭流,释放资源,但在关闭之前会先刷新流。一旦关闭,就不能再写数据

六、字符流读取数据的2种方式

方法名 说明
int read() 一次读一个字符数据
int read(char[] cbuf) 一次读一个字符数组数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package zi_fu_liu;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import javax.imageio.stream.FileImageInputStream;

public class write {
public static void main(String[] args) throws IOException{
InputStreamReader isr=new InputStreamReader(new FileInputStream("zifuliu.txt"));
//一次读一个字符
int len;
while((len=isr.read())!=-1){
System.out.print((char)len);//acbcdehello!myworld
}

System.out.println();

//一次读一个字符数组
InputStreamReader isr2=new InputStreamReader(new FileInputStream("zifuliu.txt"));
char[] cha=new char[1024];
int le;
while((le=isr2.read(cha))!=-1){
System.out.println(new String(cha,0,le));//acbcdehello!myworld
}

isr.close();
isr2.close();
}
}

案例:复制文件

分析:

①转换流的名字较长,而常见的操作都是按照本地默认编码实现的,为了简化书写,转换流提供了对应的子类

  • FileReader:用于读取字符文件的便捷类

    FileReader(String fileName)

  • fileWriter:用于写入字符文件的便捷类

    FileWriter(String fileName)

数据源目的地分析

数据源:读数据—Reader抽象类用于读取字符流—其子类InputerStreamReader是从字节流到字符流的桥—FileReader

目的地:写数据—Writer用于写入字符流的抽象类—OutPutStreamWriter是字符的桥梁流以字节流—FileWriter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package zi_fu_liu;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class anli {
public static void main(String[] args) throws IOException{
FileReader fr=new FileReader("IO_/zi_fu_liu/write.java");
FileWriter fw=new FileWriter("copy.txt");

char[] cha=new char[1024];
int len;
while((len=fr.read(cha))!=-1){
System.out.print(new String(cha,0,len));
fw.write(cha,0,len);
}
fw.close();
fr.close();
}

}

七、字符缓冲流

  • BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小。默认值足够大,可用于大多数用途
  • BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。默认值足够大,可用于大多数用途

构造方法

  • BufferedWriter(Writer out)
  • BufferedReader(Reader in)

用字符缓冲流复制文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package zi_fu_liu;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Buffer_ {
public static void main(String[] args) throws IOException{
BufferedReader br=new BufferedReader(new FileReader("IO_/zi_fu_liu/write.java"));
BufferedWriter bw=new BufferedWriter(new FileWriter("copy2.txt"));

//一次读写一个字符数据
// int len;
// while((len=br.read())!=-1){
// bw.write(len);
// }

//一次读写一个字符数组
char[] cha=new char[1024];
int le;
while((le=br.read(cha))!=-1){
bw.write(cha,0,le);
}
br.close();
bw.close();
}
}

字符缓冲流特有功能

BufferedWriter:

  • void newLine():写一个行分隔符,行分隔符字符串由系统属性定义

BufferedReader:

  • public String readLine():读一行文字。结果包含行的内容的字符串,不包括任何行终止字符,如果流的结尾已经到达,则为null

八、小结

字节流

字符流

请我喝杯咖啡吧~

支付宝
微信