IO流(二)IO流中异常捕获方式、字符集和底层实现以及出现的问题的详细讲解,字符流的详细讲解,字节和字符流的综合练习
(3)IO流中异常的捕获方式
package ByteInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class ByteStreamDemo6 { public static void main(String[] args) throws FileNotFoundException { FileInputStream fis = null; FileOutputStream fos = null; /* 基本做法:手动释放资源 */ try { fis = new FileInputStream("E:\\java.File\\bbb\\屏幕截图 2026-04-14 215600.png"); fos = new FileOutputStream("opp-IO\\p.png"); int len; byte[] bytes = new byte[1024 * 1024 * 5]; while ((len = fis.read(bytes)) != -1) { fos.write(bytes, 0 ,len); } } catch (IOException e) { e.printStackTrace(); } finally { if (fos != null) { try { fos.close(); }catch (IOException e) { e.printStackTrace(); } } if (fis != null) { try { fis.close(); }catch (IOException e) { e.printStackTrace(); } } } /*JDK7:IO流中的捕获异常写法 try后面的小括号中写创建对象的代码, 注意:只有实现了AutoCloseable接口的类,才能在小括号中创建对象 (而FileInputStream和FileOutputStream都实现了该接口类) AutoCloseable接口特点:在特定情况下,可以自动实现释放资源 try(){ }catch() { } */ try(FileInputStream fis = new FileInputStream("E:\\java.File\\bbb\\屏幕截图 2026-04-14 215600.png"); FileOutputStream fos = new FileOutputStream("opp-IO\\p.png") ) { int len; byte[] bytes = new byte[1024 * 1024 * 5]; while ((len = fis.read(bytes)) != -1) { fos.write(bytes, 0 ,len); } }catch (IOException e) { e.printStackTrace(); } /* JDK9以后 */ FileInputStream fis = new FileInputStream("E:\\java.File\\bbb\\屏幕截图 2026-04-14 215600.png"); FileOutputStream fos = new FileOutputStream("opp-IO\\p.png"); try(fis;fos) { int len; byte[] bytes = new byte[1024 * 1024 * 5]; while ((len = fis.read(bytes)) != -1) { fos.write(bytes, 0 ,len); } }catch (IOException e) { e.printStackTrace(); } } }(4)字符集
引入:字节流读取文件时,文件中不能出现中文,否则读取出来的是乱码现象
字符集分类:
ASCII 英文
GBK 英文 中文
Unicode 英文 中文
—1、ASCII字符集
ASCII字符集
存储英文,一个字节就足以。
—2、GBK字符集
GBK字符集
Windows系统默认使用的就是GBK。系统显示:ANSI
计算机的存储规则(英文)(GBK)和ASSCII存储方式一样
规则:英文一个字节存储,兼容ASCII,二进制前面补0.
计算机的存储规则(汉字)(GBK)
规则1:一个汉字两个字节存储(第一个字节叫高位字节,第二个字节叫低位字节)
规则2:高位字节二进制一定以1开头,转成十进制之后是一个负数
核心1:GBK中,一个英文字符一个字节,二进制第一位是0
核心2:GBK中,一个中文汉字两个字节,二进制第一位是1
—3、Unicode字符集
Unicode字符集
国际标准字符集,它将世界各种语言的每个字符定义一个唯一的编码,以满足跨语言,跨平台的文本信息转换
UTF-8是Unicode字符集的一种编码方式
UTF-8编码规则:用1~4个字节保存(ASCII还是用一个字节,而中文汉字用3个字节,中文第一个字节是1)
注意:
一个英文占一个字节,二进制第一位是 0,转成十进制是正数
一个中文占三个字节,二进制第一位是 1,第一个字节转成十进制是负数
—4、乱码出现原因及解决方案
为什么会出现乱码?
原因1:读取数据时未读完整个汉字(字节流一次读取一个字符)
原因2:编码和解码时的方式不统一
如何不产生乱码:
不要用字节流读取文本文件
编码解码时使用同一个码表文件,同一个编码方式
—5、java中编码和解码的常用方法
java中编码的方法
String类中的方法
public byte[] getBytes() 使用默认方式进行编码
注:str.getBytes()→ 无参,默认 UTF-8(IDEA 现在默认 UTF-8),1 个中文占 3 字节
Public byte[] getBytes(String charsetName) 使用指定方式进行编码
注:str.getBytes("GBK")→ GBK 编码,1 个中文占 2 字节
java中解码的方法
String类中的方法
String(byte[] bytes) 使用默认方式进行解码
注:str.getBytes("GBK")→ GBK 编码,1 个中文占 2 字节
String(byte[] bytes, String charsetName) 使用指定方式进行解码
注:new String(bytes1,"GBK"):UTF-8 的字节,强行用 GBK 规则解析 → 编码解码不一致 → 乱码
public class ByteStreamDemo7 { public static void main(String[] args) throws IOException { //1、编码 String str = "ai你邮"; byte[] bytes1 = str.getBytes(); System.out.println(Arrays.toString(bytes1)); byte[] bytes2 = str.getBytes("GBK"); System.out.println(Arrays.toString(bytes2)); //2、解码 String str2 = new String(bytes1); System.out.println(str2); String str3 = new String(bytes1,"GBK"); System.out.println(str3); } }(5)字符流
字符流
字符流的底层其实就是字节流
字符流=字节流+字符集
特点
输入流:一次读一个字节,遇到中文时,一次读多个字节
输出流:底层会把数据按照指定的编码方式进行编码,变成字节再写到文件中
使用场景
对纯文本文件进行读写操作
—1、字符输入流
FileReader
(1)创建字符输入流对象
Public FileReader(File file) 创建字符输入流关联本地文件
Public FileReader(String pathname) 创建字符输入流关联本地文件
细节1:如果文件不存在,就直接报错
(2)读取数据
Public int read() 读取数据,读到末尾返回-1
Public int read(char[] buffer) 读取多个数据,读到末尾返回-1
无参read方法细节:按字节进行读取一次读一个字节,遇到中文,一次读取多个字节。读取后解码并转成十进制,返回一个整数,如果想看到中文汉字或者英文,再进行强转就可以了。
有参read方法细节:把读取字节,解码,强转三步合并,强转后的字符放到数组中
细节2:读到文件末尾了,read方法返回-1.
(3)释放资源
Public int close 释放资源/关流
package CharStream; import java.io.FileReader; import java.io.IOException; public class CharStreamDemo2 { public static void main(String[] args) throws IOException { FileReader fr = new FileReader("opp-IO\\a.txt"); int ch; while ((ch = fr.read()) != -1) { System.out.print((char)ch); } char[] chars = new char[3]; /* read(chars)有参方法: 读取数据,解码,强转三步合并了,把强转之后的字符放到数组当中 read()空参 : read + 强制类型转换 */ int len; while ((len = fr.read(chars)) != -1) { //把数组中的数据变成字符串再进行打印 System.out.println(new String(chars,0,len)); } fr.close(); } }—2、字符输出流
FileWriter构造方法
Public FileWriter(File file) 创建字符输出流关联本地文件
Public FileWriter(String pathname) 创建字符输出流关联本地文件
Public FileWriter(File file, boolean append) 创建字符输出流关联本地文件,续写
Public FileWriter(String pathname, boolean append) 创建字符输出流关联本地文件,续写
FileWriter成员方法
Void write(int c) 写出一个字符
Void write(String str) 写出一个字符串
Void write(String str, int off, int len) 写出一个字符串的一部分
Void write(char[] cbuf) 写出一个字符数组
Void write(char[] cbuf, int off, int len) 写出字符数组的一部分
FileWriter书写细节
(1)创建字符输出流对象
细节1:参数是字符串表示的路径或者File对象都是可以的
细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的
细节3:如果文件已经存在,则会清空文件,如果不想清空可以打开续写开关
(2)写数据
细节:如果write方法的参数是整数,但是实际上写到本地文件中的是整数在字符集上对应的字符
(3)释放资源
细节:每次使用完流之后都要释放资源
package CharStream; import java.io.FileWriter; import java.io.IOException; public class CharStreamDemo3 { public static void main(String[] args) throws IOException { FileWriter fw = new FileWriter("opp-IO\\a.txt",true); //1、一次写一个字符如果遇到中文,UTF-8中文3个字节,GBK中文2个字节 fw.write(25105); fw.write("\r\n"); //2、写一个字符串 fw.write("我在精神病院学斩神"); fw.write("\r\n"); //3、写出一个字符数组 char[] chars = {'o','k',',','我','要','修','仙'}; fw.write(chars); fw.close(); } }6)字节流和字符流的使用场景和综合练习
字符流和字节流的使用场景
字节流
拷贝任意类型的文件
字符流
读取纯文本文件中的数据
往纯文本文件中写出数据
——1、拷贝一个文件夹
package Text; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class Text1 { public static void main(String[] args) throws IOException { //1、创建对象表示数据源 File src = new File("E:\\java.File\\bbb"); //2、创建对象表示目的地 File dest = new File("E:\\java.File\\Text.opp\\aaa"); copydir(src,dest); } /* 参数一:数据源 参数二:目的地 */ private static void copydir(File src, File dest) throws IOException { //如果dest文件不存在,则创建一个新的 dest.mkdirs(); //递归 //1、进入数据源 File[] files = src.listFiles(); //2、遍历数组 for (File file : files) { if(file.isFile()) { //3、判断文件,拷贝 FileInputStream fis = new FileInputStream(file);//拷贝到dest文件夹里面的文件中, // 所以父级路径是dest,子级路径是dest里面的文件 FileOutputStream fos = new FileOutputStream(new File(dest,file.getName())); byte[] bytes = new byte[1024]; int len; while ((len = fis.read(bytes)) != -1) { fos.write(bytes, 0, len); } fos.close(); fis.close(); }else { //判断文件夹,递归 copydir(file, new File(dest,file.getName())); } } } }——2、加密和解密文件
package Text; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class Text2 { public static void main(String[] args) throws IOException { /* ^ : 异或 两边相同:false 两边不同:true 如果异或两边是数字,先把两边变成二进制,然后逐位判断 100 ^ 10的结果是110 110 ^ 10的结果是100 所以可以利用上面的特性加密文件(先后异或一个数字) */ //1、创建对象关联原始文件 FileInputStream fis = new FileInputStream("opp-IO\\a.txt"); //2、创建对象关联加密文件 FileOutputStream fos = new FileOutputStream("opp-IO\\b.txt"); int b; while ((b = fis.read()) != -1) { fos.write(b ^ 2); } /* 如果我此时想看加密文件,则只需要把加密文件作为原始文件,在创建一个关联文件,进行解密即可 FileInputStream fis = new FileInputStream("opp-IO\\b.txt"); FileOutputStream fos = new FileOutputStream("opp-IO\\c.txt"); int b; while ((b = fis.read()) != -1) { fos.write(b ^ 2); } */ fos.close(); fis.close(); } }——3、修改文件中的数据
package Text; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.function.Function; public class Text3 { public static void main(String[] args) throws IOException { /* 文本文件中数据: 2-1-8-4-7-8 要求:将文件中的数据进行排序,变成以下的数据:1-2-4-7-8-9 */ //1、获取数据 FileReader fr = new FileReader("opp-IO\\a.txt"); StringBuilder sb = new StringBuilder(); int ch; while((ch = fr.read()) != -1) { sb.append((char)ch); } fr.close(); System.out.println(sb); //2、排序 // String str = sb.toString(); // String[] arrStr = str.split("-"); // // ArrayList<Integer> list = new ArrayList<>(); // for(String s : arrStr) { // int i = Integer.parseInt(s); // list.add(i); // } // Collections.sort(list); // System.out.println(list); Integer[] arr = Arrays.stream(sb.toString().split("-")) .map(new Function<String, Integer>() { @Override public Integer apply(String s) { return Integer.parseInt(s); } }).sorted() .toArray(Integer[]::new); System.out.println(Arrays.toString(arr)); //3、写出 FileWriter fw = new FileWriter("opp-IO\\a.txt"); String s = Arrays.toString(arr).replace(", ","-"); String result = s.substring(1,s.length()-1); fw.write(result); fw.close(); // FileWriter fw = new FileWriter("opp-IO\\a.txt"); // for (int i = 0; i < list.size(); i++) { // if(i==list.size()-1) { // fw.write(list.get(i) + ""); // }else { // fw.write(list.get(i) + "-"); // } // } // fw.close(); } }