IO流
字符流
为什么会出现字符流
- 字符流的介绍
- 由于字节流操作中文不是特别的方便,所以Java就提供字符流
- 字符流 = 字节流 + 编码表
- 中文的字节存储方式
- 用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接成中文,如何识别是中文的呢?
- 汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream=new FileInputStream("BasicGrammar\\abc123.txt");
FileOutputStream fileOutputStream=new FileOutputStream("BasicGrammar\\abc.txt");
//如果一次读一个字节 中文将出现乱码
// int by;
// while((by=fileInputStream.read())!=-1){
// fileOutputStream.write((char)by);
// System.out.println((char)by);
// }
byte [] bytes=new byte[1024];
int len;
while ((len=fileInputStream.read(bytes))!=-1){
fileOutputStream.write(bytes,0,len);
System.out.println(new String(bytes));
}
}
编码表
- 基础知识:
- 计算机中存储的信息都是用二进制数表示的,我们在屏幕上看到的英文、汉字是二进制转换后的结果
- 按照某种规则,将字符存储在计算机中,称之为编码。反之,将存储在计算机中的二进制数按照某种规则解析出来,称之为解码。
- 按照A编码进行存储,必须按照A编码解析,这样才能显示正确的文本符,否则就会导致乱码现象。
- 字符编码:就是一套自然语言的字符与二进制数之间的对应规则(A,65)
- 字符集:
- 是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等
- 计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBXXX字符集、Unicode字符集等
- 常见的字符集
- lASCII:
- 是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)
- 基本的ASCII字符集,使用7位表示一个字符,共128字符。ASCII的扩展字符集使用8位表示一个字符,共256字符,方便支持欧洲常用字符。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等
- GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等
- Unicode字符集:
- UTF-8编码:可以用来表示Unicode标准中任意字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。它使用一至四个字节为每个字符编码
- 编码规则:
- 128个US-ASCII字符,只需一个字节编码
- 拉丁文等字符,需要二个字节编码
- 大部分常用字(含中文),使用三个字节编码
- 其他极少使用的Unicode辅助字符,使用四字节编码
- lASCII:
- 采用何种规则编码,就要采用对应规则解码,否则就会出现乱码
字符串中的编码解码问题
- 编码
- 解码
//编码、解码
public static void main(String[] args) throws UnsupportedEncodingException {
String str="中国";
//编码操作
byte[] bytes = str.getBytes();
System.out.println(Arrays.toString(bytes));//[-28, -72, -83, -27, -101, -67]
byte[] bytes1 = str.getBytes("utf-8");
System.out.println(Arrays.toString(bytes1));//[-28, -72, -83, -27, -101, -67]
byte[] bytes2 = str.getBytes("GBK");
System.out.println(Arrays.toString(bytes2));//[-42, -48, -71, -6]
//解码操作
String s = new String(bytes);
System.out.println(s);//中国
String s1 = new String(bytes1,"utf-8");
System.out.println(s1);//中国
String s2 = new String(bytes2,"GBK");
System.out.println(s2);//中国
}
字符流中的编码解码问题
- 字符流抽象基类
- Reader:字符输入流的抽象类
- Writer:字符输出流的抽象类
- 字符流中和编码解码问题相关的两个
- inputStreamReader:是从字节流到字符流的桥梁,它读取字节,并使用指定的编码将其解码为字符,它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
- OutputStreamWriter:是从字符流到字节流的桥梁,是从字符流到字节流的桥梁,使用指定的编码将写入的字符编码为字节,它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
- 构造方法
public static void main(String[] args) throws IOException {
Writer outputStreamReader=new OutputStreamWriter(new FileOutputStream("F:\\abc.txt"),"GBK");
Reader inputStreamReader=new InputStreamReader(new FileInputStream("F:\\abc.txt"),"GBK");
outputStreamReader.write("中国");
一次读取一个字符数据
int ch;
while((ch=inputStreamReader.read())!=-1) {
System.out.println((char)ch);
}
inputStreamReader.close();
outputStreamReader.close();
}
字符流写数据的5种方式
//字符流写数据的5种方式
public static void main(String[] args) throws IOException {
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("F:\\phx.txt"));
//方式一:每次写一个字符
// osw.write(97);
// osw.write(98);
// osw.write(99);
// //phx.txt:abc
// osw.close();
//方式二:写入一个字符数组
// char[] chars= {'a','b','c','d'};
// osw.write(chars);
// //phx.txt:abcd
// osw.close();
//方式三:写入字符数组的一部分
// char[] chars= {'a','b','c','d'};
// osw.write(chars,1,chars.length-1);
// //phx.txt:bcd
// osw.close();
//方式四:写入字符串
// String str="Hello,World";
// osw.write(str);
// //phx.txt:Hello,World
// osw.close();
//方式五:写一个字符串的一部分
String str="Hello,Word";
int len=str.length();
//第一个5代表的是要获取的字符串的开始位置,第二个5表示从开始开始位置开始获取的字符个数
osw.write(str,5,5);
//phx.txt:,Word
osw.close();
}
字符流读数据的2种方式
//字符流读数据的2种方式
public static void main(String[] args) throws IOException {
Reader reader=new InputStreamReader(new FileInputStream("F:\\phx.txt"),"utf-8");
//方式一:一次读一个字符
// int ch;
// while((ch=reader.read())!=-1) {
// System.out.print((char)ch+" ");//H e l l o , W o r d ! 你 好
// }
// reader.close();
//方式二:一次读取一个字符数组
char[]chars=new char[1024];
int len;
while((len=reader.read(chars))!=-1) {
System.out.println(new String(chars));//Hello,Word!你好
}
reader.close();
}
字符流复制Java文件
//根据数据源创建字符输入流对象
Reader isr= new InputStreamReader(new FileInputStream("F:\\HelloServlet.java"));
//根据目的地创建字符输出流对象
Writer osw=new OutputStreamWriter(new FileOutputStream("F:\\phx.java"));
//读写数据,复制文件
//一次读写一个字符数据
// int ch;
// while((ch=isr.read())!=-1) {
// osw.write(ch);
// }
// isr.close();
// osw.close();
int len;
char[] chars=new char[1024];
while((len=isr.read(chars))!=-1) {
osw.write(chars, 0, len);
}
释放资源
isr.close();
osw.close();
}
字符流复制Java文件改进版
public static void main(String[] args) throws IOException {
//根据数据源创建字符输入流对象
//Reader isr= new InputStreamReader(new FileInputStream("F:\\HelloServlet.java"));
Reader fr=new FileReader("F:\\\\HelloServlet.java");
//根据目的地创建字符输出流对象
//Writer osw=new OutputStreamWriter(new FileOutputStream("F:\\phx.java"));
Writer fw=new FileWriter("F:\\phx.java");
//读写数据,复制文件
//一次读写一个字符数据
// int ch;
// while((ch=isr.read())!=-1) {
// osw.write(ch);
// }
// isr.close();
// osw.close();
int len;
char[] chars=new char[1024];
while((len=fr.read(chars))!=-1) {
fw.write(chars, 0, len);
}
释放资源
fr.close();
fw.close();
}
字符缓冲流
- 字符缓冲流介绍
- BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小。默认值足够大,可用于大多数用途
- BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途
- 构造方法
public static void main(String[] args) throws IOException {
//字符缓冲流
BufferedWriter bw=new BufferedWriter(new FileWriter("F:\\abc.txt"));
BufferedReader br=new BufferedReader(new FileReader("F:\\abc.txt"));
bw.write("Hello,\r\n");
bw.write("你好");
bw.close();//必须先关闭,否则后面不执行
char []chars=new char[1024];
int len;
while((len=br.read(chars))!=-1) {
System.out.print(new String(chars,0,len));
}
br.close();
}
字符缓冲流复制Java文件
//字符缓冲流复制Java文件
BufferedWriter bw=new BufferedWriter(new FileWriter("F:\\phx.java"));
BufferedReader br=new BufferedReader(new FileReader("F:\\HelloServlet.java"));
char []chars=new char[1024];
int len;
while((len=br.read(chars))!=-1) {
bw.write(chars);
}
br.close();
bw.close();
}
字符缓冲流特有功能
public static void main(String[] args) throws IOException {
//创建字符缓冲输出流
BufferedWriter bw=new BufferedWriter(new FileWriter(new File("F:\\phx.txt")));
//写数据
for(int i=0;i<10;i++) {
bw.write("hello world"+i);
bw.newLine();
bw.flush();
}
//释放资源
bw.close();
BufferedReader br=new BufferedReader(new FileReader("F:\\phx.txt"));
String line;
while((line=br.readLine())!=null) {
System.out.println(line);
}
br.close();
}
字符缓冲流特有功能复制Java文件
public static void main(String[] args) throws IOException {
BufferedReader br=new BufferedReader(new FileReader("F:\\HelloServlet.java"));
BufferedWriter bw=new BufferedWriter(new FileWriter("F:\\phx.java"));
//读写数据,复制文件
//使用字符缓冲流特有功能实现
String line;
while((line=br.readLine())!=null) {
bw.write(line);
bw.newLine();
bw.flush();
}
br.close();
bw.close();
}
IO流小结
字节流
小结:字节流可以复制任意文件数据,有四种方式,一般采用字节缓冲流一次读写一个字节数组的方式。
字符流
小结:字符流只能复制文本数据,有5种方式,一般采用字符缓冲流的特有功能。
案例
把ArrayList集合中的学生数据写入到文本文件,把文本文件中的数据读取到集合中,并遍历集合
public class Demo12 {
public static void main(String[] args) throws IOException {
List<Student> list=new ArrayList<>();
Student stu1=new Student(1, "张三", 18, "男", "上海市浦东新区");
Student stu2=new Student(1, "李四", 18, "男", "上海市徐汇区");
Student stu3=new Student(1, "王五", 18, "男", "上海市普陀区");
Student stu4=new Student(1, "小明", 18, "男", "上海市宝山区");
list.add(stu1);
list.add(stu2);
list.add(stu3);
list.add(stu4);
BufferedWriter bw=new BufferedWriter(new FileWriter("F:\\phx.txt"));
//通过for循环把集合中的学生写入文件
for(Student stu:list) {
bw.write(stu.toString());
bw.newLine();
bw.flush();
}
bw.close();
BufferedReader br=new BufferedReader(new FileReader("F:\\phx.txt"));
String line="";
List<Student> students=new ArrayList<>();
//获取文件中的每一行信息赋值给学生
while((line=br.readLine())!=null) {
String[] strs=line.split(",");
Student stu=new Student(Integer.parseInt(strs[0]),strs[1],Integer.parseInt(strs[2]),strs[3],strs[4]);
students.add(stu);
}
for(Student stu:students) {
System.out.println(stu);
}
}
}
//学生实体类
public class Student {
private int id;
private String name;
private int age;
private String sex;
private String address;
public Student(int id, String name, int age, String sex, String address) {
this.id = id;
this.name = name;
this.age = age;
this.sex = sex;
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return id + "," + name + "," + age + "," + sex + "," + address ;
}
}