在完成对C语言的学习后,我最近开始了对C++和Java的学习,目前跟着视频学习了一些语法,也跟着敲了一些代码,有了一定的掌握程度。现在将跟着视频做的笔记进行整理。本篇博客是整理Java知识点的第二十四篇博客。
本篇博客介绍了Java的字符流。
本系列博客所有Java代码都使用IntelliJ IDEA编译运行,版本为2022.1。所用JDK版本为JDK11。
目录
字符流
出现字符流的原因
字节流操作中文等语言不是特别方便,因此提供了字符流。字符流 = 字节流 + 编码表
字节流复制文件出现中文时,结果没有问题,因为最终底层操作通过编码表自动拼接成中文。
编码表
计算机存储的信息都是二进制表示的,屏幕上的内容都是进行了转换的结果。
按照某种规则,将字符存储到计算机中,称为编码。将存储到计算机中的二进制数按照某种规则解析显示出来,就是解码。使用哪种码进行编码,就使用哪种码进行解码,否则会出现乱码。
字符编码是字符与数字的对应规则。
字符集是系统支持的所有字符的集合,包括各国语言文字,标点符号,数字等。计算机要准确存储各种字符集符号,就要进行字符编码,常见的有ASCII字符集,GBXXX字符集,Unicode字符集等。
ASCII码是美国信息交换标准代码,基于拉丁字母,用于显示现代英语。包括控制字符和可显示字符(大小写,数字,英文符号等)。
GB2312是信息交换用汉字编码字符集。用两个字节表示一个汉字。组合了7000多个简体汉字,并兼容ASCII码。
GBK是汉字内码扩展规范,是最常用的中文码表,在GB2312的标准上进行扩展。收录了2万多个汉字,兼容GB2312,支持繁体汉字。
GB18030是信息技术 中文编码字符集,收录超过7万个汉字,用多字节编码,每个字可以有1个,2个或4个字节组成。支持繁体字和我国少数民族文字。
Unicode字符集是为了表达任意语言的任意字符设计的,称为统一码。最多4个字节来表示每个字母,符号,文字。有UTF-8,UTF-16和UTF-32三种方案,最常用的是UTF-8。
UTF-8编码可以表示Unicode标准中的任意字符。所有互联网协议都支持UTF-8编码。使用1-4个字节编码。128个ASCII码字符使用一个字节,拉丁文等字符使用两个字节,大部分常用字,包括中文,使用三个字节,极少使用的用四个字节。
字符串的编码解码问题
byte[] getBytes()使用平台的默认字符集将String编码,结果存至byte数组中。
byte[] getBytes(String charsetName)使用指定字符集将String编码,结果存至byte数组中。
String(byte[] bytes)使用默认字符集解码指定的字节数组。
String(byte[] bytes,String charsetName)通过指定字符集解码指定的字节数组。
本机使用IDEA所用编码为UTF-8。
import java.io.UnsupportedEncodingException;
public class codetest1 {
public static void main(String[] args) throws UnsupportedEncodingException {
String s = "奥运会";
byte[] byte1 = s.getBytes();
System.out.println(new String(byte1));
System.out.println(new String(byte1,"GBK"));
byte[] byte2 = s.getBytes("GBK");
System.out.println(new String(byte2));
System.out.println(new String(byte2,"GBK"));
}
}
程序的输出是:
奥运会
濂ヨ繍浼�
���˻�
奥运会
字符流的编码解码问题
Reader是字符输入流的抽象类。Writer是字符输出流的抽象类。
字符流中和编码解码问题相关的输入类是InputStreamReader,相关输出类是OutputStreamWriter。
使用这两个类也要导包,import java.io.InputStreamReader和import java.io.OutputStreamWriter。
import java.io.*;
public class codetest2 {
public static void main(String[] args) throws IOException {
OutputStreamWriter osw1 = new OutputStreamWriter(new FileOutputStream("test3.txt"),"UTF-8");
osw1.write("上午和下午");
osw1.close();
OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream("test3.txt",true),"GBK");
osw2.write("上午和下午");
osw2.close();
InputStreamReader isr1 = new InputStreamReader(new FileInputStream("test3.txt"),"UTF-8");
int ch;
while((ch = isr1.read()) != -1){
System.out.print((char)ch);
}
System.out.println();
isr1.close();
InputStreamReader isr2 = new InputStreamReader(new FileInputStream("test3.txt"),"GBK");
while((ch = isr2.read()) != -1){
System.out.print((char)ch);
}
System.out.println();
isr2.close();
}
}
程序使用OutputStreamWriter以UTF-8和GBK向文件中写入上午和下午。随后使用InputStreamReader从文件中以UTF-8和GBK的方式读入。
程序的输出是:
上午和下午���������
涓婂崍鍜屼笅鍗埳衔绾拖挛�
test3.txt的内容是:
涓婂崍鍜屼笅鍗埳衔绾拖挛?
字符流写数据的五种方式
void write(int c)写入一个字符,ASCII码值为c。
void write(char[] cbuf)写入一个字符数组。
void write(char[] cbuf,int off,int len)将cbuf从off开始的len个字符写入。
void write(String str)写入一个字符串。
void write(String str,int off,int len)将str从off开始的len个字符写入。
flush()刷新流,将数据保存,之后还可以继续写入数据。
close()关闭流,释放资源。关闭前会刷新,关闭后无法继续写数据。
import java.io.*;
public class writetest6 {
public static void main(String[] args) throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("test3.txt"));
osw.write(50);
char[] ch = new char[]{'a','b','c','d','e'};
osw.write(ch);
osw.write(ch,2,2);
osw.write("北京冬奥会");
osw.write("Beijing 2022",2,3);
osw.close();
}
}
程序无输出,文件中的内容是:
2abcdecd北京冬奥会iji
字符流读数据的二种方式
int read()一次读一个字符数据,并将其码值返回。
int read(char[] cbuf)一次读一个字符数组数据,并返回读取的字符数量。
读到文件结尾后都返回-1。
import java.io.*;
public class readtest3 {
public static void main(String[] args) throws IOException {
InputStreamReader isr1 = new InputStreamReader(new FileInputStream("test3.txt"));
int ch;
while((ch = isr1.read()) != -1){
System.out.print((char)ch);
}
System.out.println();
isr1.close();
InputStreamReader isr2 = new InputStreamReader(new FileInputStream("test3.txt"));
char[] chr = new char[1024];
int len;
while((len = isr2.read(chr)) != -1){
System.out.println(new String(chr, 0, len));
}
isr2.close();
}
}
程序的输出是:
2abcdecd北京冬奥会iji
2abcdecd北京冬奥会iji
字符流复制Java文件
字符流的名字比较长,我们通常使用本地默认编码。因此Java提供了对应子类。
FileReader用于读取字符文件,构造方法为FileReader(String fileName),需要导包,import java.io.FileReader。
FileWriter用于写入字符文件,构造方法为FileWriter(String fileName),需要导包,import java.io.FileWriter。
import java.io.*;
public class readwritetest2 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("pokertest2.Java");
FileWriter fw = new FileWriter("pokertest3.Java");
char[] chs = new char[1024];
int len;
while((len = fr.read(chs)) != -1){
fw.write(chs,0,len);
}
fr.close();
fw.close();
}
}
同样使用两个流处理,一个读一个写。程序无输出。由于内容太长,就不再展示,复制成功。
字符缓冲流
BufferedWriter将文本写入字符输出流,缓冲字符以提供高效写入。可以指定缓冲区大小,或者使用默认大小。默认值足够大。需要导包,import java.io.BufferedWriter。构造方法是:
BufferedWriter(Writer out)
BufferedReader从字符输入流读取文本,缓冲字符以提供高效读取。可以指定缓冲区大小或使用默认大小,默认值足够大。需要导包,import java.io.BufferedReader。构造方法是:
BufferedReader(Reader in)
import java.io.*;
public class buffertest2 {
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("test3.txt"));
bw.write(97);
bw.write(98);
bw.write(99);
bw.write(100);
bw.write(10);
bw.write("Hello Java");
bw.write("\n");
bw.close();
BufferedReader br = new BufferedReader(new FileReader("test3.txt"));
char[] chr = new char[1024];
int len = 0;
while((len = br.read(chr)) != -1){
System.out.print(new String(chr, 0, len));
}
br.close();
}
}
程序先向一个文件中写数据,然后从这个文件中读数据。
程序的输出是:
abcd
Hello Java
文件操作也成功。
字符缓冲流特有功能
BufferedWriter的void newLine()进行换行。
BufferedReader的public String readLine()读一行文字,将结果返回。结果不包含换行符,到末尾后返回null。
import java.io.*;
public class bufferreadwrite {
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("test3.txt"));
bw.write("Hello Java");
bw.newLine();
bw.write("2022 07 18");
bw.newLine();
bw.write("After 17");
bw.newLine();
bw.write("This is in JDK11");
bw.close();
BufferedReader br = new BufferedReader(new FileReader("test3.txt"));
String s;
while((s = br.readLine()) != null){
System.out.println(s);
}
br.close();
}
}
程序同样先向一个文件写数据,然后从这个文件中读数据。
程序的输出是:
Hello Java
2022 07 18
After 17
This is in JDK11
文件内容也成功改变。
import java.io.*;
public class buffertest3 {
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("pokertest3.java"));
BufferedReader br = new BufferedReader(new FileReader("pokertest2.java"));
String s;
while((s = br.readLine()) != null){
bw.write(s);
bw.newLine();
}
bw.close();
br.close();
}
}
可以据此改进复制Java文件的程序,程序复制成功。
IO流小结
字节流分为字节输入流InputStream和字节输出流OutputStream。InputStream包括FileInputStream和BufferedInputStream。OutputStream包括FileOutputStream和BufferedOutputStream。
字符流包括字符输入流Reader和字符输出流Writer。Reader包括InputStreamReader和BufferedReader,InputStreamReader包括FileReader。Writer包括OutputStreamWriter和BufferedWriter,OutputStreamWriter包括FileWriter。
一般使用字节缓冲流和字符缓冲流。另外,IO流的名字容易混。