Java基础——I/O
一、异常
异常是程序中可能出现的问题,它的父类是Exception。异常分为两类,编译时异常、运行时异常。
- 编译时异常:没有继承RuntimeException的异常,直接继承于Exception。编译阶段就会错误提示。
- 运行时异常:RuntimeException本身和子类。编译阶段没有错误提示,运行时有异常会提示。
JVM默认处理异常的方式:
1.把异常的名称,异常原因及异常出现的位置等信息输出在了控制台
2.程序停止执行。异常下面的代码不会再执行。
public class ExceptionDemo6 {public static void main(String[] args) {/*自己处理(捕获异常)格式:try {可能出现异常的代码;} catch(异常类名 变量名) {异常的处理代码;}好处:可以让程序继续往下执行,不会停止*/int[] arr = {1, 2, 3, 4, 5, 6};try{//可能出现异常的代码;System.out.println(arr[10]);//此处出现了异常,程序就会在这里创建一个ArrayIndexOutOfBoundsException对象//new ArrayIndexOutOfBoundsException();//拿着这个对象到catch的小括号中对比,看括号中的变量是否可以接收这个对象//如果能被接收,就表示该异常就被捕获(抓住),执行catch里面对应的代码//当catch里面所有的代码执行完毕,继续执行try...catch体系下面的其他代码}catch(ArrayIndexOutOfBoundsException e){//如果出现了ArrayIndexOutOfBoundsException异常,我该如何处理System.out.println("索引越界了");}System.out.println("看看我执行了吗?");}
}
关于异常的四个问题:
1.如果try中没有遇到问题,怎么执行?
会把try里面所有的代码全部执行完毕,不会执行catch里面的代码
注意: 只有当出现了异常才会执行catch里面的代码
2.如果try中可能会遇到多个问题,怎么执行?
会写多个catch与之对应
细节: 如果我们要捕获多个异常,这些异常中如果存在父子关系的话,那么父类一定要写在下面
在JDK7之后,我们可以在catch中同时捕获多个异常,中间用|进行隔开
表示如果出现了A异常或者B异常的话,采取同一种处理方案
3.如果try中遇到的问题没有被捕获,怎么执行?
相当于try…catch的代码白写了,最终还是会交给虚拟机进行处理。
4. 如果try中遇到了问题,那么try下面的其他代码还会执行吗?
下面的代码就不会执行了,直接跳转到对应的catch当中,执行catch里面的语句体,但是如果没有对应catch与之匹配,那么还是会交给虚拟机进行处理
异常中的常见方法
- public String getMessage() 返回此 throwable 的详细消息字符串
- public String toString() 返回此可抛出的简短描述
- public void printStackTrace() 在底层是利用System.err.println进行输出
把异常的错误信息以红色字体输出在控制台
细节:仅仅是打印信息,不会停止程序运行
int[] arr = {1, 2, 3, 4, 5, 6};try {System.out.println(arr[10]);} catch (ArrayIndexOutOfBoundsException e) {String message = e.getMessage();System.out.println(message);//Index 10 out of bounds for length 6String str = e.toString();System.out.println(str);//java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 6e.printStackTrace();}System.out.println("看看我执行了吗?");//正常的输出语句//System.out.println(123);//错误的输出语句(而是用来打印错误信息)//System.err.println(123);}
}
抛出异常
- throws:写在方法定义处,表示声明一个异常。告诉调用者,使用本方法可能会有哪些异常。
- throw :写在方法内,结束方法。手动抛出异常对象,交给调用者。方法中下面的代码不再执行了。
public class ExceptionDemo12 {public static void main(String[] args) {
/*需求:定义一个方法求数组的最大值
*/int[] arr = null;int max = 0;try {max = getMax(arr);} catch (NullPointerException e) {System.out.println("空指针异常");} catch (ArrayIndexOutOfBoundsException e) {System.out.println("索引越界异常");}System.out.println(max);}public static int getMax(int[] arr)/* throws NullPointerException,ArrayIndexOutOfBoundsException*/{if(arr == null){//手动创建一个异常对象,并把这个异常交给方法的调用者处理//此时方法就会结束,下面的代码不会再执行了throw new NullPointerException();}if(arr.length == 0){//手动创建一个异常对象,并把这个异常交给方法的调用者处理//此时方法就会结束,下面的代码不会再执行了throw new ArrayIndexOutOfBoundsException();}System.out.println("看看我执行了吗?");int max = arr[0];for (int i = 1; i < arr.length; i++) {if(arr[i] > max){max = arr[i];}}return max;}
}
二、文件File
FIle概述和构造方法
1.File对象表示路径,可以是文件、也可以是文件夹。这个路径可以是存在的,也可以是不存在的
2.绝对路径带盘符,相对路径不带盘符,默认到当前项目下去找
public class FileDemo1 {public static void main(String[] args) {/*public File(String pathname) 根据文件路径创建文件对象public File(String parent, String child) 根据父路径名字符串和子路径名字符串创建文件对象public File(File parent, String child) 根据父路径对应文件对象和子路径名字符串创建文件对象C:\Users\alienware\Desktop\:转义字符*///1.根据字符串表示的路径,变成File对象String str = "C:\\Users\\alienware\\Desktop\\a.txt";File f1 = new File(str);System.out.println(f1);//C:\Users\alienware\Desktop\a.txt//2.父级路径:C:\Users\alienware\Desktop//子级路径:a.txtString parent = "C:\\Users\\alienware\\Desktop";String child = "a.txt";File f2 = new File(parent,child);System.out.println(f2);//C:\Users\alienware\Desktop\a.txtFile f3 = new File(parent + "\\" + child);System.out.println(f3);//C:\Users\alienware\Desktop\a.txt//3.把一个File表示的路径和String表示路径进行拼接File parent2 = new File("C:\\Users\\alienware\\Desktop");String child2 = "a.txt";File f4 = new File(parent2,child2);System.out.println(f4);//C:\Users\alienware\Desktop\a.txt}
}
File的成员方法
public class FileDemo2 {public static void main(String[] args) throws IOException{/*public boolean isDirectory() 判断此路径名表示的File是否为文件夹public boolean isFile() 判断此路径名表示的File是否为文件public boolean exists() 判断此路径名表示的File是否存在*///1.对一个文件的路径进行判断File f1 = new File("D:\\aaa\\a.txt");System.out.println(f1.isDirectory());//falseSystem.out.println(f1.isFile());//trueSystem.out.println(f1.exists());//trueSystem.out.println("--------------------------------------");//2.对一个文件夹的路径进行判断File f2 = new File("D:\\aaa\\bbb");System.out.println(f2.isDirectory());//trueSystem.out.println(f2.isFile());//falseSystem.out.println(f2.exists());//trueSystem.out.println("--------------------------------------");//3.对一个不存在的路径进行判断File f3 = new File("D:\\aaa\\c.txt");System.out.println(f3.isDirectory());//falseSystem.out.println(f3.isFile());//falseSystem.out.println(f3.exists());//false//---------------------------------------------------------------------/*public long length() 返回文件的大小(字节数量)public String getAbsolutePath() 返回文件的绝对路径public String getPath() 返回定义文件时使用的路径public String getName() 返回文件的名称,带后缀public long lastModified() 返回文件的最后修改时间(时间毫秒值)*///1.length 返回文件的大小(字节数量)//细节1:这个方法只能获取文件的大小,单位是字节//如果单位我们要是M,G,可以不断的除以1024//细节2:这个方法无法获取文件夹的大小//如果我们要获取一个文件夹的大小,需要把这个文件夹里面所有的文件大小都累加在一起。File f1 = new File("D:\\aaa\\a.txt");long len = f1.length();System.out.println(len);//12File f2 = new File("D:\\aaa\\bbb");long len2 = f2.length();System.out.println(len2);//0System.out.println("====================================");//2.getAbsolutePath 返回文件的绝对路径File f3 = new File("D:\\aaa\\a.txt");String path1 = f3.getAbsolutePath();System.out.println(path1);File f4 = new File("myFile\\a.txt");String path2 = f4.getAbsolutePath();System.out.println(path2);System.out.println("====================================");//3.getPath 返回定义文件时使用的路径File f5 = new File("D:\\aaa\\a.txt");String path3 = f5.getPath();System.out.println(path3);//D:\aaa\a.txtFile f6 = new File("myFile\\a.txt");String path4 = f6.getPath();System.out.println(path4);//myFile\a.txtSystem.out.println("====================================");//4.getName 获取名字//细节1://a.txt:// a 文件名// txt 后缀名、扩展名//细节2://文件夹:返回的就是文件夹的名字File f7 = new File("D:\\aaa\\a.txt");String name1 = f7.getName();System.out.println(name1);File f8 = new File("D:\\aaa\\bbb");String name2 = f8.getName();System.out.println(name2);//bbbSystem.out.println("====================================");//5.lastModified 返回文件的最后修改时间(时间毫秒值)File f9 = new File("D:\\aaa\\a.txt");long time = f9.lastModified();System.out.println(time);//1667380952425
//---------------------------------------------------------------------/*public boolean createNewFile() 创建一个新的空的文件public boolean mkdir() 创建单级文件夹public boolean mkdirs() 创建多级文件夹public boolean delete() 删除文件、空文件夹*///1.createNewFile 创建一个新的空的文件//细节1:如果当前路径表示的文件是不存在的,则创建成功,方法返回true// 如果当前路径表示的文件是存在的,则创建失败,方法返回false//细节2:如果父级路径是不存在的,那么方法会有异常IOException//细节3:createNewFile方法创建的一定是文件,如果路径中不包含后缀名,则创建一个没有后缀的文件/*File f1 = new File("D:\\aaa\\ddd");boolean b = f1.createNewFile();System.out.println(b);//true*///2.mkdir make Directory,文件夹(目录)//细节1:windows当中路径是唯一的,如果当前路径已经存在,则创建失败,返回false//细节2:mkdir方法只能创建单级文件夹,无法创建多级文件夹。/* File f2 = new File("D:\\aaa\\aaa\\bbb\\ccc");boolean b = f2.mkdir();System.out.println(b);*///3.mkdirs 创建多级文件夹//细节:既可以创建单级的,又可以创建多级的文件夹File f3 = new File("D:\\aaa\\ggg");boolean b = f3.mkdirs();System.out.println(b);//true
//---------------------------------------------------------------------/*public boolean delete() 删除文件、空文件夹细节:如果删除的是文件,则直接删除,不走回收站。如果删除的是空文件夹,则直接删除,不走回收站如果删除的是有内容的文件夹,则删除失败*///1.创建File对象File f1 = new File("D:\\aaa\\eee");//2.删除boolean b = f1.delete();System.out.println(b);//public File[] listFiles() 获取当前该路径下所有内容//1.创建File对象File f = new File("D:\\aaa");//2.listFiles方法//作用:获取aaa文件夹里面的所有内容,把所有的内容放到数组中返回File[] files = f.listFiles();for (File file : files) {//file依次表示aaa文件夹里面的每一个文件或者文件夹System.out.println(file);}
//---------------------------------------------------------------------/*public static File[] listRoots() 列出可用的文件系统根public String[] list() 获取当前该路径下所有内容public String[] list(FilenameFilter filter) 利用文件名过滤器获取当前该路径下所有内容(掌握)public File[] listFiles() 获取当前该路径下所有内容public File[] listFiles(FileFilter filter) 利用文件名过滤器获取当前该路径下所有内容public File[] listFiles(FilenameFilter filter) 利用文件名过滤器获取当前该路径下所有内容*//* //1.listRoots 获取系统中所有的盘符File[] arr = File.listRoots();System.out.println(Arrays.toString(arr));//2.list() 获取当前该路径下所有内容(仅仅能获取名字)File f1 = new File("D:\\aaa");String[] arr2 = f1.list();for (String s : arr2) {System.out.println(s);}*///3.list(FilenameFilter filter) 利用文件名过滤器获取当前该路径下所有内容//需求:我现在要获取D:\\aaa文件夹里面所有的txt文件File f2 = new File("D:\\aaa");//accept方法的形参,依次表示aaa文件夹里面每一个文件或者文件夹的路径//参数一:父级路径//参数二:子级路径//返回值:如果返回值为true,就表示当前路径保留// 如果返回值为false,就表示当前路径舍弃不要String[] arr3 = f2.list(new FilenameFilter() {@Overridepublic boolean accept(File dir, String name) {File src = new File(dir,name);return src.isFile() && name.endsWith(".txt");}});System.out.println(Arrays.toString(arr3));}
}//---------------------------------------------------------------------/*(掌握)public File[] listFiles() 获取当前该路径下所有内容public File[] listFiles(FileFilter filter) 利用文件名过滤器获取当前该路径下所有内容public File[] listFiles(FilenameFilter filter) 利用文件名过滤器获取当前该路径下所有内容*///1.创建File对象File f = new File("D:\\aaa");//2.需求:打印里面所有的txt文件File[] arr = f.listFiles();for (File file : arr) {//file依次表示aaa文件夹里面每一个文件或者文件夹的路径if(file.isFile() && file.getName().endsWith(".txt")){System.out.println(file);}}
//---------------------------------------------------------------------//创建File对象File f = new File("D:\\aaa");//调用listFiles(FileFilter filter)File[] arr1 = f.listFiles(new FileFilter() {@Overridepublic boolean accept(File pathname) {return pathname.isFile() && pathname.getName().endsWith(".txt");}});//调用listFiles(FilenameFilter filter)File[] arr2 = f.listFiles(new FilenameFilter() {@Overridepublic boolean accept(File dir, String name) {File src = new File(dir, name);return src.isFile() && name.endsWith(".txt");}});System.out.println(Arrays.toString(arr2));
三、I/O流(字节流、字符流)
I/O流是指存储和读取数据的解决方案:I表示input,O表示output。
I/O流用于读写数据,如本地文件、网络等。
输出流是从程序到文件,输入流是从文件到程序
I/O流分为字节流和字符流。
字节流:可以操作所有类型的文件
字符流:只能操作纯文本文件(用windows系统自带的记事本打开并且能读懂的文件,如txt文件,md文件,xml文件,lrc文件等)
字节输出流
字节输出流的基本用法
public class ByteStreamDemo1 {public static void main(String[] args) throws IOException {/** 演示:字节输出流FileOutputStream* 实现需求:写出一段文字到本地文件中。(暂时不写中文)** 实现步骤:* 创建对象* 写出数据* 释放资源* *///1.创建对象//写出 输出流 OutputStream//本地文件 FileFileOutputStream fos = new FileOutputStream("myio\\a.txt");//2.写出数据fos.write(97);//3.释放资源fos.close();}
}
字节输出流的细节
public class ByteStreamDemo2 {public static void main(String[] args) throws IOException {/*字节输出流的细节:1.创建字节输出流对象细节1:参数是字符串表示的路径或者是File对象都是可以的细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的。细节3:如果文件已经存在,则会清空文件2.写数据细节:write方法的参数是整数,但是实际上写到本地文件中的是整数在ASCII上对应的字符‘9’‘7’3.释放资源每次使用完流之后都要释放资源*///1.创建对象FileOutputStream fos = new FileOutputStream("myio\\a.txt");//2.写出数据fos.write(57);fos.write(55);//3.释放资源fos.close();while(true){}}
}
字节输出流写出数据三种方式
public class ByteStreamDemo3 {public static void main(String[] args) throws IOException {/*void write(int b) 一次写一个字节数据void write(byte[] b) 一次写一个字节数组数据void write(byte[] b, int off, int len) 一次写一个字节数组的部分数据参数一:数组参数二:起始索引 0参数三:个数 3*///1.创建对象FileOutputStream fos = new FileOutputStream("myio\\a.txt");//2.写出数据//fos.write(97); // a//fos.write(98); // bbyte[] bytes = {97, 98, 99, 100, 101};/* fos.write(bytes);*/fos.write(bytes,1,2);// b c//3.释放资源fos.close();}
}
换行和续写
public class ByteStreamDemo4 {public static void main(String[] args) throws IOException {/*换行写:再次写出一个换行符就可以了windows: \r\nLinux: \nMac: \r细节:在windows操作系统当中,java对回车换行进行了优化。虽然完整的是\r\n,但是我们写其中一个\r或者\n,java也可以实现换行,因为java在底层会补全。建议:不要省略,还是写全了。续写:如果想要续写,打开续写开关即可开关位置:创建对象的第二个参数默认false:表示关闭续写,此时创建对象会清空文件手动传递true:表示打开续写,此时创建对象不会清空文件*///1.创建对象FileOutputStream fos = new FileOutputStream("myio\\a.txt",true);//2.写出数据String str = "kankelaoyezuishuai";byte[] bytes1 = str.getBytes();fos.write(bytes1);//再次写出一个换行符就可以了String wrap = "\r\n";byte[] bytes2 = wrap.getBytes();fos.write(bytes2);String str2 = "666";byte[] bytes3 = str2.getBytes();fos.write(bytes3);//3.释放资源fos.close();}
}
字节输入流
字节输入流的基本用法
public class ByteStreamDemo1 {public static void main(String[] args) throws IOException {/** 演示:字节输入流FileInputStream* 实现需求:读取文件中的数据。(暂时不写中文)** 实现步骤:* 创建对象* 读取数据* 释放资源* *///1.创建对象FileInputStream fis = new FileInputStream("myio\\a.txt");//2.读取数据int b1 = fis.read();System.out.println((char)b1);int b2 = fis.read();System.out.println((char)b2);int b3 = fis.read();System.out.println((char)b3);int b4 = fis.read();System.out.println((char)b4);int b5 = fis.read();System.out.println((char)b5);int b6 = fis.read();System.out.println(b6);//-1//3.释放资源fis.close();}
}
字节输入流的细节
public class ByteStreamDemo2 {public static void main(String[] args) throws IOException {/*字节输入流的细节:1.创建字节输入流对象细节1:如果文件不存在,就直接报错。Java为什么会这么设计呢?输出流:不存在,创建把数据写到文件当中输入流:不存在,而是报错呢?因为创建出来的文件是没有数据的,没有任何意义。所以Java就没有设计这种无意义的逻辑,文件不存在直接报错。程序中最重要的是:数据。2.写数据细节1:一次读一个字节,读出来的是数据在ASCII上对应的数字细节2:读到文件末尾了,read方法返回-1。3.释放资源细节:每次使用完流之后都要释放资源*///1.创建对象FileInputStream fis = new FileInputStream("myio\\b.txt");//2.读取数据int b1 = fis.read();System.out.println((char)b1);//3.释放资源fis.close();}
}
字节输入流循环读取
public class ByteStreamDemo3 {public static void main(String[] args) throws IOException {/*字节输入流循环读取*///1.创建对象FileInputStream fis = new FileInputStream("myio\\a.txt");//2.循环读取int b;while ((b = fis.read()) != -1) {System.out.println((char) b);}//3.释放资源fis.close();/* *//*** read :表示读取数据,而且是读取一个数据就移动一次指针** *//*FileInputStream fis = new FileInputStream("myio\\a.txt");//2.循环读取while ((fis.read()) != -1) {System.out.println(fis.read());//98 100 -1}//3.释放资源fis.close();*/}
}
文件拷贝基本代码
public class ByteStreamDemo4 {public static void main(String[] args) throws IOException {/** 练习:* 文件拷贝* 把D:\movie.mp4拷贝到当前模块下。** 注意:* 选择一个比较小的文件,不要太大。**** 课堂练习:* 要求统计一下拷贝时间,单位毫秒* */long start = System.currentTimeMillis();//1.创建对象FileInputStream fis = new FileInputStream("D:\\itheima\\movie.mp4");FileOutputStream fos = new FileOutputStream("myio\\copy.mp4");//2.拷贝//核心思想:边读边写int b;while((b = fis.read()) != -1){fos.write(b);}//3.释放资源//规则:先开的最后关闭fos.close();fis.close();long end = System.currentTimeMillis();System.out.println(end - start);}
}
文件拷贝弊端和解决方案
将数据读到字节数组byte[]中,将byte[]转成字符串一定要带着后面的0,len两个参数。
public class ByteStreamDemo5 {public static void main(String[] args) throws IOException {/*public int read(byte[] buffer) 一次读一个字节数组数据*///1.创建对象FileInputStream fis = new FileInputStream("myio\\a.txt");//2.读取数据byte[] bytes = new byte[2];//一次读取多个字节数据,具体读多少,跟数组的长度有关//返回值:本次读取到了多少个字节数据int len1 = fis.read(bytes);System.out.println(len1);//2String str1 = new String(bytes,0,len1);System.out.println(str1);int len2 = fis.read(bytes);System.out.println(len2);//2String str2 = new String(bytes,0,len2);System.out.println(str2);int len3 = fis.read(bytes);System.out.println(len3);// 1String str3 = new String(bytes,0,len3);System.out.println(str3);// ed//3.释放资源fis.close();}
}
文件拷贝改写
public class ByteStreamDemo6 {public static void main(String[] args) throws IOException {/** 练习:* 文件拷贝* 把D:\movie.mp4 (16.8 MB) 拷贝到当前模块下。** */long start = System.currentTimeMillis();//1.创建对象FileInputStream fis = new FileInputStream("D:\\movie.mp4");FileOutputStream fos = new FileOutputStream("myio\\copy.mp4");//2.拷贝int len;byte[] bytes = new byte[1024 * 1024 * 5];while((len = fis.read(bytes)) != -1){fos.write(bytes,0,len);}//3.释放资源fos.close();fis.close();long end = System.currentTimeMillis();System.out.println(end - start);}
}
I/O流不同版本捕获异常的方式
基本做法
public class ByteStreamDemo7 {public static void main(String[] args) {/*** 利用try...catch...finally捕获拷贝文件中代码出现的异常*** *///1.创建对象FileInputStream fis = null;FileOutputStream fos = null;try {fis = new FileInputStream("D:\\movie.mp4");fos = new FileOutputStream("myio\\copy.mp4");//2.拷贝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 {//3.释放资源if(fos != null){try {fos.close();} catch (IOException e) {e.printStackTrace();}}if(fis != null){try {fis.close();} catch (IOException e) {e.printStackTrace();}}}}
}
JDK7方案
public class ByteStreamDemo8 {public static void main(String[] args) {/*** JDK7:IO流中捕获异常的写法** try后面的小括号中写创建对象的代码,* 注意:只有实现了AutoCloseable接口的类,才能在小括号中创建对象。* try(){** }catch(){** }** */try (FileInputStream fis = new FileInputStream("D:\\movie.mp4");FileOutputStream fos = new FileOutputStream("myio\\copy.mp4")) {//2.拷贝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方案
public class ByteStreamDemo9 {public static void main(String[] args) throws FileNotFoundException {/*** JDK9:IO流中捕获异常的写法*** */FileInputStream fis = new FileInputStream("D:\\movie.mp4");FileOutputStream fos = new FileOutputStream("myio\\copy.mp4");try (fis;fos) {//2.拷贝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();}}
}
字符集
在计算机中,任何数据都是以二进制的形式来存储
ASCII字符集中,一个英文占一个字节
GBK字符集中,一个英文占一个字节,二进制第一位是0,一个中文占两个字节,二进制高位字节的第一位是1
Unicode字符集的UTF-8编码格式,一个英文占一个字节,二进制第一位是0,一个中文占三个字节,二进制第一位是1。
有乱码的原因
- 读取数据时未读完整个汉字
- 编码和解码的方式不统一
如何不产生乱码
- 不要用字节流读取文本文件
- 编码解码时用一个码表,同一个编码方式
编码和解码
public class CharSetDemo3 {public static void main(String[] args) throws UnsupportedEncodingException {/*Java中编码的方法public byte[] getBytes() 使用默认方式进行编码public byte[] getBytes(String charsetName) 使用指定方式进行编码Java中解码的方法String(byte[] bytes) 使用默认方式进行解码String(byte[] bytes, String charsetName) 使用指定方式进行解码*///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);}
}
字符输入流
字符流=字节流+字符集
输入流:一次读一个字节,遇到中文时,一个读多个字节
输出流:底层会把数据按照指定的编码方式进行编码,变成字节再写到文件中
使用场景为纯文本文件读写操作
无参read方法讲解
public class CharStreamDemo1 {public static void main(String[] args) throws IOException {/*第一步:创建对象public FileReader(File file) 创建字符输入流关联本地文件public FileReader(String pathname) 创建字符输入流关联本地文件第二步:读取数据public int read() 读取数据,读到末尾返回-1public int read(char[] buffer) 读取多个数据,读到末尾返回-1第三步:释放资源public void close() 释放资源/关流*///1.创建对象并关联本地文件FileReader fr = new FileReader("myio\\a.txt");//2.读取数据 read()//字符流的底层也是字节流,默认也是一个字节一个字节的读取的。//如果遇到中文就会一次读取多个,GBK一次读两个字节,UTF-8一次读三个字节//read()细节://1.read():默认也是一个字节一个字节的读取的,如果遇到中文就会一次读取多个//2.在读取之后,方法的底层还会进行解码并转成十进制。// 最终把这个十进制作为返回值// 这个十进制的数据也表示在字符集上的数字// 英文:文件里面二进制数据 0110 0001// read方法进行读取,解码并转成十进制97// 中文:文件里面的二进制数据 11100110 10110001 10001001// read方法进行读取,解码并转成十进制27721// 我想看到中文汉字,就是把这些十进制数据,再进行强转就可以了int ch;while((ch = fr.read()) != -1){System.out.print((char)ch);}//3.释放资源fr.close();}
}
有参read方法讲解
public class CharStreamDemo2 {public static void main(String[] args) throws IOException {/*第一步:创建对象public FileReader(File file) 创建字符输入流关联本地文件public FileReader(String pathname) 创建字符输入流关联本地文件第二步:读取数据public int read() 读取数据,读到末尾返回-1public int read(char[] buffer) 读取多个数据,读到末尾返回-1第三步:释放资源public void close() 释放资源/关流*///1.创建对象FileReader fr = new FileReader("myio\\a.txt");//2.读取数据char[] chars = new char[2];int len;//read(chars):读取数据,解码,强转三步合并了,把强转之后的字符放到数组当中//空参的read + 强转类型转换while((len = fr.read(chars)) != -1){//把数组中的数据变成字符串再进行打印System.out.print(new String(chars,0,len));}//3.释放资源fr.close();}
}