0x00 概述
本文涉及Java知识点有字节缓冲流,字符流。
0x01 字节缓冲流
1.1 字节缓冲流构造方法
- 字节缓冲流介绍
BufferOutputStream:该类实现缓冲输出流,通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节频繁调用系统底层
BufferInputStream: 创建BufferedInputStream将创建一个内部缓冲区数组,当从流中读取或者跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节
构造方法
示例
package BufferStreamDemo; import java.io.*; public class BufferStreamDemo { public static void main(String[] args) throws IOException { // 字节缓冲输出流: BufferedOutputStream(OutputStream out) BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream ("C:\\Users\\119k\\IdeaProjects\\d18\\src\\BufferStreamDemo\\fos.txt")); // 写数据 bos.write("hello\r\n".getBytes()); bos.write("world\r\n".getBytes()); // 释放资源 bos.close(); // 字节缓冲输入流 : BufferedInputStream(InputStream in) BufferedInputStream bis = new BufferedInputStream(new FileInputStream ("C:\\Users\\119k\\IdeaProjects\\d18\\src\\BufferStreamDemo\\fos.txt")); /* // 一次读取一个字节数据 int by; while ((by = bis.read()) != -1) { System.out.println((char) by); } System.out.println("--------------"); */ // 一次读取一个字节数组的数据 byte[] bys = new byte[1024]; int len; while ((len = bis.read(bys)) != -1) { System.out.println(new String(bys, 0, len)); } bis.close(); } }
1.2 字节流复制视频
- 需求:把 E:\itcast\字节流复制图片.avi 复制到模块目录下的 字节流复制图片.avi
- 实现步骤:
根据数据源创建字节输入流对象
根据目的地创建 字节输出流对象
读写数据,复制视频
释放资源
示例
package CopyVideoDemo; import java.io.*; public class CopyVideoDemo { public static void main(String[] args) throws IOException { // 记录开始时间 long startTime = System.currentTimeMillis(); // 复制视频 // method1(); // method2(); // method3(); method4(); // 记录结束时间 long endtime = System.currentTimeMillis(); System.out.println("共耗时:" + (endtime - startTime) + "毫秒"); } // 字节缓冲流一次读写一个字节数组 public static void method4() throws IOException { BufferedInputStream bis = new BufferedInputStream( new FileInputStream("C:\\Users\\119k\\IdeaProjects\\d18\\src\\CopyVideoDemo\\mn.avi") ); BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream("C:\\Users\\119k\\IdeaProjects\\d18\\src\\CopyVideoDemo\\mn2.avi") ); byte[] bys = new byte[1024]; int len; while ((len = bis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); bis.close(); } // 字节缓冲流一次读写一个字节 public static void method3() throws IOException { BufferedInputStream bis = new BufferedInputStream( new FileInputStream("C:\\Users\\119k\\IdeaProjects\\d18\\src\\CopyVideoDemo\\mn.avi") ); BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream("C:\\Users\\119k\\IdeaProjects\\d18\\src\\CopyVideoDemo\\mn2.avi") ); int by; while ((by = bis.read()) != -1) { bos.write(by); } bos.close(); bis.close(); } // 基本字节流一次读写一个字节数组 public static void method2() throws IOException { FileInputStream fis = new FileInputStream( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\CopyVideoDemo\\mn.avi" ); FileOutputStream fos = new FileOutputStream( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\CopyVideoDemo\\mn2.avi" ); byte[] bys = new byte[1024]; int len; while ((len = fis.read(bys)) != -1) { fos.write(bys, 0, len); } fos.close(); fis.close(); } // 基本字节流一次读写一个字节 public static void method1() throws IOException { FileInputStream fis = new FileInputStream( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\CopyVideoDemo\\mn.avi" ); FileOutputStream fos = new FileOutputStream( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\CopyVideoDemo\\mn2.avi" ); int by; while ((by = fis.read()) != -1) { fos.write(by); } fos.close(); fis.close(); } }
0x02 字符流
2.1 为什么会出现字符流
- 字符流介绍
由于字节流操作中文不是特别的方便,所以Java提供了字符流
字符流=字节流+编码表
- 中文的字节存储方式
用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接成中文,如何识别是中文的呢?
汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数
2.2 编码表
- 什么是字符集
是一个系统支持的所有字符的集合,包括各国家文字,标点符号,图形符号,数字等
计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码,常见字符集有ASCII字符集,GBXXX字符集,Unicode字符集等
- 常见的字符集
2.3 字符串中的编码解码
相关方法
示例
package StringDemo; import java.io.UnsupportedEncodingException; import java.util.Arrays; public class StringDemo { public static void main(String[] args) throws UnsupportedEncodingException { // 定义一个字符串 String s = "中国"; // byte[] bys = s.getBytes(); // [-28, -72, -83, -27, -101, -67] // byte[] bys = s.getBytes("UTF-8"); // [-28, -72, -83, -27, -101, -67] byte[] bys = s.getBytes("GBK"); // [-42, -48, -71, -6] System.out.println(Arrays.toString(bys)); // String ss = new String(bys); // String ss = new String(bys, "UTF-8"); String ss = new String(bys, "GBK"); System.out.println(ss); } }
2.4 字符流中的编码解码
- 字符流中和编码解码问题相关的两个类
InputStreamReader:从字节流到字符流的桥梁
它读取字节,并使用指定的编码及将其解码为字符
它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
OutputStreamWriter:是从字符流到字节流的桥梁,使用指定的编码将写入的字符编码为字节
它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
构造方法
示例
package ConversionStreamDemo; import java.io.*; public class ConversionStreamDemo { public static void main(String[] args) throws IOException { /* OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\ConversionStreamDemo\\osw.txt") ); */ OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\ConversionStreamDemo\\osw.txt" ), "UTF-8"); osw.write("中国"); osw.close(); /* InputStreamReader isr = new InputStreamReader(new FileInputStream( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\ConversionStreamDemo\\osw.txt" )); */ InputStreamReader isr = new InputStreamReader(new FileInputStream( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\ConversionStreamDemo\\osw.txt" ), "UTF-8"); // 一次读取一个字符数据 int by; while ((by = isr.read()) != -1) { System.out.println((char) by); } isr.close(); } }
2.5 字符流写数据的5种方法
- 方法介绍
- 刷新和关闭的方法
示例
package OutputStreamWriterDemo; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; public class OutputStreamWriterDemo { public static void main(String[] args) throws IOException { OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\OutputStreamWriterDemo\\fos.txt" )); // void write(int c): 写一个字符 // osw.write(97); // osw.write(98); // osw.write(99); // osw.write(100); // void write(char[] cbuf) : 写入一个字符数组 // char[] chs = {'a', 'b', 'c', 'd'}; // osw.write(chs); // void write(String str) // osw.write("abcdefg"); // void write(String str, int off, int len): 写一个字符串的一部分 // osw.write("abcdefghijk", 0, "abcdefghijk".length()); osw.write("abcdefghijk", 1,3); // 释放资源 osw.close(); } }
2.6 字符流读数据的2种方法
- 方法介绍
示例
package InputStreamReaderDemo; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; public class InputStreamReaderDemo { public static void main(String[] args) throws IOException { InputStreamReader isr = new InputStreamReader(new FileInputStream( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\InputStreamReaderDemo\\isrJava.java" )); /* // int read(): 一次读一个字符数据 int ch; while ((ch = isr.read()) != -1) { System.out.println((char) ch); } */ // int read(char[] cbuf): 一次读取一个字符数组数据 char[] chs = new char[1024]; int len; while ((len = isr.read(chs)) != -1) { System.out.println(new String(chs, 0, len)); } // 释放资源 isr.close(); } }
2.7 字符流复制Java文件
- 需求:把模块目录下的“ConversionStreamDemo.java” 复制到模块目录下的“Copy.java”
- 实现步骤:
根据数据源创建字符输入流对象
根据目的地创建字符输出流对象
读写数据,复制文件
释放资源
示例
package CopyJavaDemo1; import java.io.*; public class CopyJavaDemo1 { public static void main(String[] args) throws IOException { // 根据数据源创建字符输入流对象 InputStreamReader isr = new InputStreamReader(new FileInputStream( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\CopyJavaDemo1\\isrJava.java" )); // 根据目的地创建字符输出流对象 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\CopyJavaDemo1\\isrJava2.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); } // 释放资源 osw.close(); isr.close(); } }
2.8 字符流复制Java文件改进版
- 需求: 使用字符流对象,把模块目录下的“ConversionStreamDemo.java” 复制到模块目录下的“Copy.java”
- 实现步骤:
根据数据源创建字符输入流对象
根据目的地创建字符输出流对象
读写数据,复制文件
释放资源
示例
package CopyJavaDemo2; import java.io.FileWriter; import java.io.IOException; import java.io.FileReader; public class CopyJavaDemo2 { public static void main(String[] args) throws IOException { // 根据数据源创建字符输入流对象 FileReader fr = new FileReader("C:\\Users\\119k\\IdeaProjects\\d18\\src\\CopyJavaDemo2\\isrJava.java"); // 根据目的地创建字符输出流对象 FileWriter fw = new FileWriter("C:\\Users\\119k\\IdeaProjects\\d18\\src\\CopyJavaDemo2\\isrJava2.java"); // 读写数据,复制文件 /* int ch; while ((ch = fr.read()) != -1) { fw.write(ch); } */ char[] chs = new char[1024]; int len; while ((len = fr.read(chs)) != -1) { fw.write(chs, 0, len); } } }
2.9 字符缓冲流
字符缓冲流介绍
BufferWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高校写入,可以指定缓冲区大小,或者可以接受默认大小,默认值足够大,可用于大多数用途
BufferReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者使用默认大小,默认值足够大,可用于大多数用途
构造方法
示例
package BufferedStreamDemo; import java.io.*; public class BufferStreamDemo { public static void main(String[] args) throws IOException { // BufferedWriter(write out) BufferedWriter bw = new BufferedWriter(new FileWriter( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\BufferedStreamDemo\\bw.txt" )); bw.write("hello\r\n"); bw.write("world\r\n"); bw.close(); // BufferedReader(Reader in) BufferedReader br = new BufferedReader(new FileReader( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\BufferedStreamDemo\\bw.txt" )); // 一次读取一个字符数据 /* int ch; while ((ch = br.read()) != -1) { System.out.println((char) ch); } */ // 一次读取一个字符数组数据 char[] chs = new char[1024]; int len; while ((len = br.read(chs)) != -1) { System.out.println(new String(chs, 0, len)); } br.close(); } }
2.10 字符缓冲流复制Java文件
- 需求:把模块目录下的ConversionStreamDemo.java 复制到模块目录下的 Copy.java
- 实现步骤:
根据数据源创建字符缓冲输入流对象
根据目的地创建字符缓冲输出流对象
读写数据,复制文件,使用字符缓冲流特有功能实现
释放资源
示例
package BufferedStreamDemo; import java.io.*; public class BufferStreamDemo { public static void main(String[] args) throws IOException { // BufferedWriter(write out) BufferedWriter bw = new BufferedWriter(new FileWriter( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\BufferedStreamDemo\\bw.txt" )); bw.write("hello\r\n"); bw.write("world\r\n"); bw.close(); // BufferedReader(Reader in) BufferedReader br = new BufferedReader(new FileReader( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\BufferedStreamDemo\\bw.txt" )); // 一次读取一个字符数据 /* int ch; while ((ch = br.read()) != -1) { System.out.println((char) ch); } */ // 一次读取一个字符数组数据 char[] chs = new char[1024]; int len; while ((len = br.read(chs)) != -1) { System.out.println(new String(chs, 0, len)); } br.close(); } }
2.11 字符缓冲流特有功能
方法介绍
- BufferWriter
- BufferReader
示例
package BufferedStreamDemo2; import java.io.*; public class BufferedStreamDemo2 { public static void main(String[] args) throws IOException { // 创建字符缓冲输出流 BufferedWriter bw = new BufferedWriter(new FileWriter( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\BufferedStreamDemo2\\bw.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( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\BufferedStreamDemo2\\bw.txt" )); String line; while((line=br.readLine())!=null) { System.out.println(line); } br.close(); } }
2.12 字符缓冲流特有功能复制Java文件
- 需求:使用特有功能把模块目录下的ConversionStreamDemo.java 复制到模块目录下的 Copy.java
- 实现步骤:
根据数据源创建字符缓冲输入流对象
根据目的地创建字符缓冲输出流对象
读写数据,复制文件,使用字符缓冲流特有功能实现
释放资源
示例
package CopyJavaDemo3; import java.io.*; public class CopyJavaDemo3 { public static void main(String[] args) throws IOException { // 根据数据源创建字符缓冲输入流对象 BufferedReader br = new BufferedReader(new FileReader( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\CopyJavaDemo3\\test.java" )); // 根据目的地创建字符缓冲输出流对象 BufferedWriter bw = new BufferedWriter(new FileWriter( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\CopyJavaDemo3\\test2.java" )); // 读写数据 // 使用字符缓冲流特有功能实现 String line; while ((line = br.readLine()) != null) { bw.write(line); bw.newLine(); bw.flush(); } //释放资源 bw.close(); br.close(); } }
2.13 IO流小结
- 字节流
字节流可以复制人意文件类型,有4种方式一般采用字节缓冲流一次读写一个字节数组的方式
- 字符流
字符流只能复制文本数据,有5钟方式,一般采用字符缓冲流的特有功能
0x03 练习案例
3.1 集合到文件
- 需求:把文本文件中的数据读取到集合中,并遍历集合,要求:文件中每一行数据是一个集合元素
- 实现步骤
创建字符缓冲输入流对象
创建ArrayList集合对象
调用字符缓冲输入流对象的方法读数据
示例
package Text2ArrayListDemo; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; public class Text2ArrayListDemo { public static void main(String[] args) throws IOException { // 创建啊字符缓冲输入流 BufferedReader br = new BufferedReader(new FileReader( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\Text2ArrayListDemo\\text2.txt")); // 创建ArrayList集合对象 ArrayList<String> arr = new ArrayList<String>(); // 调用字符缓冲输入流对象的方法读取数据 String line; while ((line = br.readLine()) != null) { arr.add(line); } // 释放资源 br.close(); // 遍历集合 for(String s : arr){ System.out.println(s); } } }
3.2 文件到集合
- 需求:把ArrayList集合的字符串写入到文本文件,要求:每一个字符串元素作为文件中的一行数据
- 实现步骤:
创建ArrayList集合
往集合中存储字符串元素
创建字符缓冲输出流对象
遍历集合,得到每一个字符串的数据
调用字符缓冲输出流对象的方法写数据
释放资源
示例
package ArrayList2TextDemo; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; public class ArrayList2TextDemo { public static void main(String[] args) throws IOException { // 创建ArrayList集合 ArrayList<String> arr = new ArrayList<>(); // 往集合内添加字符串元素 arr.add("Alice"); arr.add("Bob"); arr.add("Charlie"); arr.add("Dogie"); // 创建字符缓冲输出流对象 BufferedWriter bw = new BufferedWriter(new FileWriter( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\ArrayList2TextDemo\\text2.txt")); // 遍历集合,得到每一个字符串数据 for(String s: arr) { // 调用字符缓冲输出流对象的方法写入文件 bw.write(s); bw.newLine(); bw.flush(); } // 释放资源 bw.close(); } }
3.3 点名器
案例需求:一个文件内存储了班级同学的姓名,每一个姓名占一行,要求通过程序实现随机点名
- 实现步骤:
创建字符缓冲输入流对象
创建ArrayList集合对象
调用字符缓冲输入流对象的方法读数据
把读取到的字符串数据存储到集合中
释放资源
使用Random产生一个随机数,随机数的范围在[0, 集合的长度]
把第6步产生的随机数作为索引到ArrayList集合中获取值
把第7步得到的数据输出到控制台
示例
package RandomNameDemo; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.Random; public class RandomNameDemo { public static void main(String[] args) throws IOException { // 创建字符缓冲输入流对象 BufferedReader br = new BufferedReader(new FileReader( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\RandomNameDemo\\name.txt" )); // 创建ArrayList集合对象 ArrayList<String> arr = new ArrayList<>(); // 调用字符缓冲流输入流对象的方法读取数据 String line; while ((line = br.readLine()) != null) { // 把读取到的字符串数据添加到集合中 arr.add(line); } // 释放资源 br.close(); // 使用Random产生一个随机数,随机数的范围在: [0, 集合的长度] Random r = new Random(); int index = r.nextInt(arr.size()); // 把随机数作为索引去集合内获取值 String name = arr.get(index); System.out.println("幸运儿是:" + name); } }
3.4 集合到文件改进版
- 案例需求:把ArrayList集合中的学生数据写入到文本文件中,要求:每一个学生对象的数据作为文件中的一行数据,格式:学号,姓名,年龄,居住地
- 实现步骤:
定义学生类
创建ArrayList集合
创建学生对象
把学生对象添加到集合中
创建字符缓冲输出流
遍历集合,得到每一个学生对象
把学生对象的数据拼接成指定格式的字符串
调用字符缓冲输出流对象的方法写数据
释放资源
示例
package ArrayList2FileDemo; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; public class ArrayList2FileDemo { public static void main(String[] args) throws IOException { // 创建ArrayList集合 ArrayList<Student> arr = new ArrayList<>(); // 创建学生对象 Student s1 = new Student("001", "Alice", 13, "BJ"); Student s2 = new Student("002", "Bob", 12, "SZ"); Student s3 = new Student("003", "Charlie", 15, "GZ"); Student s4 = new Student("004", "Doggie", 14, "NJ"); arr.add(s1); arr.add(s2); arr.add(s3); arr.add(s4); // 创建字符缓冲输出流对象 BufferedWriter bw = new BufferedWriter(new FileWriter( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\ArrayList2FileDemo\\Student_Object.txt" )); // 遍历结合,获取每一个学生对象 for (Student s : arr) { // 把学生对象的数据拼接成指定格式的字符串 StringBuilder sb = new StringBuilder(); sb.append(s.getSid()).append(", ").append(s.getName()).append(", ").append(s.getAge()) .append(", ").append(s.getAddress()); bw.write(sb.toString()); bw.newLine(); bw.flush(); } // 释放资源 bw.close(); } }
3.5 文件到集合改进版
- 案例需求:把ArrayList集合中的学生数据写入到文本文件中,要求:每一个学生对象的数据作为文件中的一行数据,格式:学号,姓名,年龄,居住地
- 实现步骤:
定义学生类
创建字符缓冲输入流对象
创建ArrayList集合对象
调用字符缓冲输入流对象的方法读数据
把读取到的字符串数据用split()进行分割,得到一个字符串数组
创建学生对象
把字符串数组中的每一个元素取出来对应的赋值给学生对象的成员变量值
把学生对象添加到集合
释放资源
遍历集合
示例
package ArrayList2FileDemo2; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; public class ArrayList2Demo2 { public static void main(String[] args) throws IOException { // 创建字符缓冲流输入对象 BufferedReader br = new BufferedReader(new FileReader( "C:\\Users\\119k\\IdeaProjects\\d18\\src\\ArrayList2FileDemo2\\Student_Object.txt" )); // 创建ArrayList集合对象 ArrayList<Student> arr = new ArrayList<>(); // 调用字符缓冲输入流对象的方法读数据 String line; while ((line = br.readLine()) != null) { String[] strArr = line.split(", "); // 创建学生对象 Student s = new Student(); s.setSid(strArr[0]); s.setName(strArr[1]); s.setAge(Integer.parseInt(strArr[2])); s.setAddress(strArr[3]); // 把学生对象添加到集合 arr.add(s); } // 释放资源 br.close(); // 遍历集合 for(Student s: arr) { System.out.println(s.getSid() + ", "+s.getName()+", " +s.getAge()+", "+s.getAddress()); } } }