1. 字符流
一个汉字存储:
- 如果是GBK编码,占用2个字节
- 如果是UTF-8编码,占用3个字节
package Java23;
import java.io.IOException;
import java.util.Arrays;
public class demo {
public static void main(String[] args) throws IOException {
// String s = "abc";
String s = "中国";//[-28, -72, -83, -27, -101, -67]
// byte[] bys = s.getBytes();
// byte[] bys = s.getBytes("UTF-8");//[-28, -72, -83, -27, -101, -67]
byte[] bys = s.getBytes("GBK");//[-42, -48, -71, -6]
System.out.println(s);
System.out.println(Arrays.toString(bys));
}
}
由于字节流操作中文不是特别方便,所以Java就提供字符流
字符流 = 字节流 + 编码表
用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接成中文
识别中文:
- 汉字在存储时,无论选择哪种编码存储,第一个字节都是负数
1.1 编码表
按照某种规则,将字符存储到计算机中,称为编码;反之,将存储在计算机中的二进制按照某种规则解析显示出来,称为解码。按照A规则编码,就必须按照A规则解析,防止出现乱码现象。
字符集:
- 是一个系统支持的所有字符的集合,包括国家文字、标点符号、图形符号、数字等
- 计算机要准确的存储和识别各种字符集符号就需要字符编码。常见字符编码ASCII字符集、GBXXX字符集、Unicode字符集等。
编码:
- byte[] getBytes():使用平台默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中
- byte[] getBytes(String charsetName):使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中
解码:
- String(byte[] bytes):通过使用平台的默认字符集解码指定的字节数组来构造新的String
- String(byte[] bytes,String charsetName):通过使用指定的字符集解码指定的字节数组来构造新的String
package Java23;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class demo2 {
public static void main(String[] args) throws UnsupportedEncodingException {
//定义字符串
String s = "中国";
//编码,byte[] getBytes():使用平台默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中
byte[] by = s.getBytes();//[-28, -72, -83, -27, -101, -67]
System.out.println(Arrays.toString(by));
//byte[] getBytes(String charsetName):使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中
// byte[] by1 = s.getBytes("UTF-8");//[-28, -72, -83, -27, -101, -67]
byte[] by1 = s.getBytes("GBK");//[-42, -48, -71, -6]
System.out.println(Arrays.toString(by1));
//解码
//String(byte[] bytes):通过使用平台的默认字符集解码指定的字节数组来构造新的String
String ss = new String(by);
System.out.println(ss);
//String(byte[] bytes,String charsetName):通过使用指定的字符集解码指定的字节数组来构造新的String
String sss = new String(by,"GBK");//由于编解码使用的规则不一致,导致乱码
System.out.println(sss);
}
}
1.2 字符流中的编码解码问题
字符流抽象基类
- Reader:字符输入流的抽象类
- Writer:字符输出流的抽象类
字符流中和编码解码问题相关的两个类:
- InputStreamReader:字符输入流
- OutputStreamWriter:字符输出流
package Java23;
import java.io.*;
public class demo1 {
public static void main(String[] args) throws IOException {
//OutputStreamWriter(OutputStream out) 创建一个使用默认字符编码的OutputStreamWriter。
//OutputStreamWriter(OutputStream out, Charset cs) 创建一个使用给定字符集的OutputStreamWriter。
// FileOutputStream fos = new FileOutputStream("D:\\lyy\\ja.txt");
// OutputStreamWriter osw = new OutputStreamWriter(fos);
//OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\\\lyy\\\\ja.txt"));
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\\\lyy\\\\ja.txt"),"GBK");
osw.write("中国");
osw.write("四月一号");
osw.close();
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\\\lyy\\\\ja.txt"),"GBK");
//一次读取一个字符数据
int ch;
while((ch=isr.read())!=-1){
System.out.print((char) ch);
}
isr.close();
}
}
字符流写数据的五种方式:
- flush():刷新流,还可以继续写数据
- close():关闭流,释放资源,但是在关闭前会先刷新流。一旦关闭就不能继续写数据
package Java23;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class demo3 {
public static void main(String[] args) throws IOException {
//字符流写数据的五种方式
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\lyy\\ja2.txt"));
//写一个字符
osw.write(97);
//public void flush()刷新流,使得数据添加入文件
osw.flush();
osw.write(98);
osw.flush();
osw.write(99);
//写一个字符数组
char[] chs = {'a','b','c','d'};
osw.write(chs);
//写入字符数组的一部分
osw.write(chs,0,chs.length);
osw.write(chs,1,3);
//写入字符串
osw.write("asdasj");
//写入字符串的一部分
osw.write("sadaiji",0,3);
//关闭流,先刷新,在关闭资源之前会先刷新数据
osw.close();
}
}
字符流写数据的两种方式
package Java23;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class demo4 {
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\lyy\\ja2.txt"));
//一次读一个字符数据
int ch;
while((ch=isr.read())!=-1){
System.out.print((char)ch);
}
//一次读一个字符数组
char[] chs = new char[1024];
int len;
while ((len= isr.read(chs))!=-1){
System.out.print(new String(chs,0,len));
}
isr.close();
}
}
案例复制Java文件
package Java23;
import java.io.*;
public class demo5 {
public static void main(String[] args) throws IOException {
//根据数据源创建字符输入流对象
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\lyy\\src\\java23\\demo.java"));
//根据目的地创建字符输出流对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\lyy\\copy.java"));
//读取并写入
//一次读写一个字符数据
// int ch;
// while ((ch=isr.read())!=-1){
// osw.write(ch);
// }
//
//一次读写一个字符数组
char[] chs = new char[1024];
int len;
while ((len=isr.read(chs))!=-1){
osw.write(chs,0,len);
}
//释放资源
isr.close();
osw.close();
}
}
使用FileWriter和FileReader来替代OutputStreamWriter 和InputStreamReader ,但是如要要对字符流中的编码问题进行操作,需要使用OutputStreamWriter 和InputStreamReader。
- FileReader:用于读取字符文件的便捷类,FileReader(String fileName)
- FileWriter:用于写入字符文件的便捷类,FileWriter(String fileName)
案例:复制Java文件
package Java23;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class demo6 {
public static void main(String[] args) throws IOException {
//根据数据源创建字符输入流对象
FileReader fr = new FileReader("D:\\lyy\\src\\java23\\demo2.java");
//根据数据源创建字符输出流对象
FileWriter fw = new FileWriter("D:\\lyy\\copy2.java");
//读写数据,继承自父类方法也有两种读写数据方式
//一次读一个字符数据
// int ch;
// while ((ch=fr.read())!=-1){
// fw.write(ch);
System.out.print((char)ch);
// }
//一次读写一个字符数组
char[] chs = new char[1024];
int len;
while ((len=fr.read(chs))!=-1){
fw.write(chs,0,len);
}
//释放资源
fw.close();
fr.close();
}
}
1.3 字符缓冲流
字符缓冲流:
- public class BufferedWriter extends Writer。将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入。 可以指定缓冲区大小,或者可以接受默认大小。 默认值足够大,可用于大多数用途。
- public class BufferedReader extends Reader。从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取。 可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途。
构造方法:
- BufferedWriter(Writer out)
- BufferedReader(Reader in)
package Java23;
import java.io.*;
public class demo7 {
public static void main(String[] args)throws IOException {
//字符缓冲输出流写数据
// FileWriter fw = new FileWriter("D:\\lyy\\ja.txt");
// BufferedWriter bw = new BufferedWriter(fw);
BufferedWriter bw =new BufferedWriter(new FileWriter("D:\\lyy\\ja.txt"));
//写入数据
bw.write("world\n");
bw.write("hello");
//字符缓冲输入流读数据
BufferedReader br = new BufferedReader(new FileReader("D:\\lyy\\ja2.txt"));
//读取数据
int len;
char[] chs = new char[1024];
while ((len=br.read(chs))!=-1){
System.out.print(new String(chs,0,len));
}
//释放资源
// bw.close();
br.close();
}
}
案例:Java文件复制,采用字符缓冲流
package Java23;
import java.io.*;
public class demo8 {
public static void main(String[] args) throws IOException {
//根据源文件创建字符缓冲流输入对象
BufferedReader br = new BufferedReader(new FileReader("D:\\lyy\\src\\Java23\\demo7.java"));
//根据目标文件创建字符缓冲流输出对象
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\lyy\\copy7.java"));
//读写字符
//一次读写一个字符
// int ch;
// while ((ch=br.read())!=-1){
// bw.write(ch);
// }
//一次读写一个字符数组
int len;
char[] chs = new char[1024];
while((len=br.read(chs))!=-1){
bw.write(chs,0,len);
}
//释放资源
br.close();
bw.close();
}
}
1.4 字符缓冲流特有功能
BufferWriter:
- void newLine():写一行行分割符,行分隔符字符串由系统属性定义
BufferedReader:
- public String readLine():读写一行文字。结果包含行的内容的字符串,不包括任何行终止字符,如果流的结尾已达到,则为null
package Java23;
import java.io.*;
public class demo9 {
public static void main(String[] args) throws IOException {
/* //创建字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\lyy\\ja.txt"));
//写数据
for(int i=0;i<10;i++){
bw.write("hello"+i);
// bw.write("\r\n");
bw.newLine();
bw.flush();
}
//释放资源
bw.close();
*/
//创建字符缓冲流输入对象
BufferedReader br = new BufferedReader(new FileReader("D:\\\\lyy\\\\ja.txt"));
// //读一行文字
// String line = br.readLine();
// System.out.println(line);
// //读第二行文字
// line = br.readLine();
// System.out.println(line);
//改用for循环
String line;
while ((line=br.readLine())!=null){
System.out.println(line);
}
br.close();
}
}