File:代表文本
IO流:读写数据
一. File
File是java.io.包下的类,File类的对象,用于代表当前操作系统的文件(可以是文件或文件夹)
注意:File类只能对文件本身进行操作,不能读写文件里面存储的数据
1.1 创建File类的对象
构造器 | 说明 |
public File(String pathname) | 根据文件路径创建文件对象 |
public File(String parent, String child) | 根据父路径和子路径名字创建文件对象 |
public File(File parent, String child) | 根据父路径对应文件对象和子路径名字创建文件对象 |
注意
· File对象既可以代表文件,也可以代表文件夹
· File封装的对象仅仅是一个路径名,这个路径可以是存在的,也允许是不存在的
绝对路径、相对路径
绝对路径:从盘符开始
相对路径:不带盘符,默认直接到当前工程下的目录寻找文件
public class demo {public static void main(String[] args) {//文件路径名://路径分隔符: 三种写法File f1 = new File("D:/zm/1.txt"); //指代某个具体的文件//File f1 = new File("D:\\zm\\1.txt");//File f1 = new File("D:"+File.separator+"zm"+File.separator+"1.txt");System.out.println(f1.length()); //文件大小File f2 = new File("D:/zm"); //指代某个文件夹System.out.println(f2.length());File f3 = new File("D:/zm/2.txt"); //指代某个不存在的文件System.out.println(f3.length()); //0System.out.println(f3.exists()); //false 不存在//绝对路径:带盘符的//File f4 = new File("D:\\code\\IJProject\\demo\\src\\wosun.txt");//相对路径:不带盘符,默认是直接去工程下寻找文件File f4 = new File("demo\\src\\wosun.txt");System.out.println(f4.length());}
}
1.2 常用方法:判断文件类型、获取文件信息
方法名称 | 说明 |
public boolean exists() | 判断当前文件对象,对应的文件路径是否存在,存在返回true |
public boolean isFile() | 判断当前文件对象指代的是否是文件,是文件返回true,反之false |
public boolean isDirectory() | 判断当前文件对象指代的是否是文件夹,是文件夹返回true,反之false |
public String getName() | 获取文件的名称(包含后缀) |
public long length() | 获取文件的大小,返回字节个数 |
public long lastModified() | 获取文件的最后修改时间 |
public String getPath() | 获取创建文件对象时,使用的路径 |
public String getAbsolutePath() | 获取绝对路径 |
public class demo {public static void main(String[] args) {//创建文件对象,指代某个文件File f1 = new File("D:/zm/1.txt");//创建文件对象,指代某个文件夹(不存在的)File f2 = new File("D:/wosun");//1.public boolean exists() 判断当前文件对象,对应的文件路径是否存在,存在返回trueSystem.out.println(f1.exists()); //trueSystem.out.println(f2.exists()); //false//2.public boolean isFile() 判断当前文件对象指代的是否是文件,是文件返回true,反之falseSystem.out.println(f1.isFile()); //true//3.public boolean isDirectory() 判断当前文件对象指代的是否是文件夹,是文件夹返回true,反之falseSystem.out.println(f1.isDirectory()); //false//4.public String getName() 获取文件的名称(包含后缀)System.out.println(f1.getName()); //1.txt//5.public long length() 获取文件的大小,返回字节个数System.out.println(f1.length());//6.public long lastModified() 获取文件的最后修改时间System.out.println(f1.lastModified());SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.println(sdf.format(f1.lastModified()));//7.public String getPath() 获取创建文件对象时,使用的路径System.out.println(f1.getPath()); //创建的时候是绝对路径就是绝对路径File f3 = new File("src\\wosun.txt"); //创建的时候是相对路径就是相对路径System.out.println(f3.getPath());//8.public String getAbsolutePath() 获取绝对路径System.out.println(f3.getAbsolutePath());}
}
1.3 常用方法:创建文件、删除文件
方法名称 | 说明 |
public boolean createNewFile() | 创建一个新文件(文件内容为空),创建成功返回true,反之false |
public boolean mkdir() | 用于创建文件夹,注意:只能创建一级文件夹 |
public boolean mkdirs() | 用于创建文件夹,注意:可以创建多级文件夹 |
public boolean delete() | 删除文件或空文件夹,注意:不能删除非空文件夹 |
注意:delete方法默认只能删除文件和空文件夹,删除后的文件不会进入回收站
public class demo {public static void main(String[] args) throws IOException {File f1 = new File("D:/zm/2.txt"); // 不存在的文件File f2 = new File("D:/zm/bbb/ccc/ddd"); //三级文件夹File f3 = new File("D:/zm/aaa"); //一级文件夹//1.public boolean createNewFile() 创建一个新文件(文件内容为空),创建成功返回true,反之falseSystem.out.println(f1.createNewFile()); //不存在则创建成功,存在则创建失败//2.public boolean mkdir() 用于创建文件夹,注意:只能创建一级文件夹System.out.println(f2.mkdir()); //falseSystem.out.println(f3.mkdir()); //true//3.public boolean mkdirs() 用于创建文件夹,注意:可以创建多级文件夹System.out.println(f2.mkdirs()); //true//4.public boolean delete() 删除文件或空文件夹,注意:不能删除非空文件夹System.out.println(f1.delete());System.out.println(f3.delete());System.out.println(f2.delete()); //删除"D:/zm/bbb/ccc/ddd"中的最后的空文件夹ddd}
}
1.4 常见方法:遍历文件夹
方法名称 | 说明 |
public String[] list() | 获取当前目录下所有的“一级文件名称”到一个字符串数组中去返回 |
public File[] listFiles() | 获取当前目录下所有的“一级文件对象”到一个文件对象数组中去返回 |
使用listFiles方法时的注意事项:
· 当主调是文件,或者路径不存在时,返回null
· 当主调是空文件夹,返回一个长度为0的数组
· 当主调是一个有内容的文件夹时,将里面所有一级文件和文件夹的路径放在File数组中返回
· 当主调是一个文件夹,且里面有隐藏文件时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
· 当主调是一个文件夹,但是没有权限访问该文件夹时,返回null
public class demo {public static void main(String[] args) throws IOException {File f1 = new File("D:/zm");//1.public String[] list() 获取当前目录下所有的“一级文件名称”到一个字符串数组中去返回String[] nameList = f1.list();for (String s : nameList) {System.out.println(s); //文件名称 eg:1.txt}//2.public File[] listFiles() 获取当前目录下所有的“一级文件对象”到一个文件对象数组中去返回//使用listFiles方法时的注意事项://· 当主调是一个有内容的文件夹时,将里面所有一级文件和文件夹的路径放在File数组中返回File[] files1 = f1.listFiles();for (File file : files1) {System.out.println(file); //文件对象 eg:D:\zm\1.txt}//· 当主调是文件,或者路径不存在时,返回nullFile f2 = new File("D:/zm/1.txt"); //主调是文件File[] files2 = f2.listFiles();System.out.println(files2); //nullFile f3 = new File("D:/recourse"); //路径不存在File[] files3 = f3.listFiles();System.out.println(files3); //null//· 当主调是空文件夹,返回一个长度为0的数组File f4 = new File("D:/zm/bbb"); //主调是空文件夹File[] files4 = f4.listFiles();System.out.println(Arrays.toString(files4)); //[]//· 当主调是一个文件夹,且里面有隐藏文件时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件//· 当主调是一个文件夹,但是没有权限访问该文件夹时,返回null}
}
二. 方法递归
· 递归是一种算法,在程序设计语言中广泛使用
· 从形式上说:方法调用自身的形式称为方法递归(recursion)
递归的形式
· 直接递归:方法自己调用自己
· 间接递归:方法调用其他方法,其他方法又回调方法自己
使用方法递归时需要注意的问题:
· 递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出错误
public class demo {public static void main(String[] args) {test1(); //java.lang.StackOverflowError 栈内存溢出错误}//直接方法递归public static void test1(){System.out.println("===test1===");test1();}//间接方法递归public static void test2(){System.out.println("===test2===");test3();}public static void test3(){test2();}
}
2.1 递归算法三要素
· 递归的公式:f(n)=f(n-1)*n
· 递归的终结点:f(1)
· 递归的方向必须走向终结点
2.2 递归算法案例
2.2.1 案例:n的阶乘
public class demo {public static void main(String[] args) {System.out.println("6的阶乘:"+f(6));}public static int f(int n){//终结点if(n==1){return 1;}else{return f(n-1)*n;}}
}
2.2.2 案例:1-n的和
public class demo {public static void main(String[] args) {System.out.println("1-100的和:"+f(100));}public static int f(int n){//终结点if(n==1){return 1;}else{return f(n-1)+n;}}
}
2.2.3 猴子吃桃问题
public class demo {public static void main(String[] args) {// 猴子吃桃问题// f(10)=1// f(x)表示f(x+1)的前一天// f(x) = 2 * (f(x+1) + 1)// 求 f(1)System.out.println("猴子第一天摘的桃子个数:" + f(1));}public static int f(int n){//终结点if(n==10){return 1;}else{return 2 * (f(n+1) + 1);}}
}
2.2.4 啤酒问题
问题:啤酒2元一瓶,4个盖子可以换一瓶,2个瓶子可以换一瓶,10块钱可以喝到几瓶?
public class demo {public static int totalNum = 0; //酒的总共数量public static int lastBottleNum = 0; //剩余的瓶子数public static int lastCoverNum = 0; //剩余的瓶盖数public static void main(String[] args) {//问题:啤酒2元一瓶,4个盖子可以换一瓶,2个瓶子可以换一瓶,10块钱可以喝到几瓶?buy(10);System.out.println("购买的酒的数量:"+totalNum);System.out.println("剩余瓶盖数:"+lastCoverNum);System.out.println("剩余瓶子数:"+lastBottleNum);}private static void buy(int money) {//买酒的数量int buyNum = money / 2;totalNum += buyNum;//当前剩余的瓶子数和瓶盖数lastBottleNum += buyNum;lastCoverNum += buyNum;int allMoney = 0; //可以换的钱数(4个盖子可值2元,2个瓶子可值2元)if(lastCoverNum >= 4){allMoney += (lastCoverNum/4)*2;}lastCoverNum = lastCoverNum % 4;if(lastBottleNum >= 2){allMoney += (lastBottleNum/2)*2;}lastBottleNum = lastBottleNum % 2;if(allMoney>=2){buy(allMoney);}}
}
2.3 递归与File
2.3.1 案例:文件搜索
public class demo {public static void main(String[] args) throws IOException {File dir = new File("D:/"); //要搜索的路径(目录)String fileName = "QQ.exe"; //要搜索的文件名searchFile(dir,fileName);}/*** 去目录下搜索某个文件* @param dir 目录* @param fileName 要搜索的文件名*/public static void searchFile(File dir,String fileName) throws IOException {//拦截非法情况(路径为null,路径不存在)if(dir == null || !dir.exists()){return; //无法搜索}//指定路径是一个文件if(dir.isFile()){//判断该文件名是否是搜索的文件名if(dir.getName().equals(fileName)){//是,打印路径System.out.println(dir.getAbsolutePath());return; //跳出方法}else{return; //搜索失败}}//指定路径dir不是null,且存在,且是一个文件夹(目录)//获取当前目录下的全部一级文件对象File[] files = dir.listFiles();//判断当前目录下是否存在一级文件对象,是否可以拿到一级文件对象if(files != null && files.length > 0){//遍历全部一级文件对象for (File file : files) {//判断文件是文件还是文件夹if(file.isFile()){//是文件if(file.getName().equals(fileName)){System.out.println(file.getAbsolutePath());//启动该程序Runtime runtime = Runtime.getRuntime();runtime.exec(file.getAbsolutePath());return; //结束方法}}else if(file.isDirectory()){//是文件夹 重复该过程searchFile(file,fileName);}}}}
}
2.3.2 案例:删除文件夹
public class demo {public static void main(String[] args) throws IOException {File dir = new File("D:/桌面/aaa");//System.out.println(dir.delete()); //false 非空文件夹不能通过delete()方法删除deleteDir(dir);}//删除非空文件夹public static void deleteDir(File dir){//指定路径为null或不存在if(dir == null || !dir.exists()){System.out.println("删除失败,指定路径为null或不存在");return;}//指定路径是文件,直接删除if(dir.isFile()){dir.delete();return;}//dir存在且是文件夹//判断dir是否为空文件夹//提取dir目录下的一级文件对象File[] files = dir.listFiles();//files为null,没有删除权限if(files == null){System.out.println("没有删除权限");return;}//因为删除内容后依旧要删除自己,所以这一段代码可以省略
// //files.length为0,说明dir是空文件夹
// if(files.length == 0){
// dir.delete();
// return;
// }//dir是一个有内容的文件夹(先删除里里面的内容再删除自己)//先删除里里面的内容for (File file : files) {if(file.isFile()){file.delete();}else{deleteDir(file);}}//再删除自己dir.delete();}
}
三. 字符集
3.1 标准ASCII字符集
· ASCII(American Standard Code for Information Interchange):美国信息交换标准代码,包括了英文、数字、符号等
· 标准ASCII使用1个字节存储一个字符,首尾是0,总共可表示128个字符
3.2 GBK(汉字内码扩展规范,国标)
· 汉字编码字符集,包含了2万多个汉字等字符,GBK中一个中文字符编码成两个字节的形式存储
· 注意:GBK兼容了ASCII字符集(英文、数字占1个字节)
· GBK规定:汉字的第一个字节的第一位必须是1
3.3 Unicode字符集(统一码,也叫万国码)
· Unicode是国际组织指定的,可以容纳世界上所有文字、符号的字符集
· UTF-32用4个字节表示一个字符(占存储空间,效率变低)
· UTF-8是Unicode字符集的一种编码方案,采用可变长编码方案,共分四个长度区:1个字节、2个字节、3个字节、4个字节
· UTF-8中英文字符、数字等只占1个字节(兼容标准ASCII编码),汉字字符占用3个字节
注意:
· 字符编码时使用的字符集,和解码时使用的字符集必须一致,否则会出现乱码
· 英文、数字一般不会乱码,因为很多字符集都兼容了ASCII编码
3.4 字符集的编码、解码
编码:把字符按照指定字符集编码成字节
解码:把字节按照指定字符集解码成字符
Java代码完成对字符的编码
String提供了如下方法 | 说明 |
byte[] getBytes() | 使用平台的默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中 |
byte[] getBytes(String charsetName) | 使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中 |
Java代码完成对字符的解码
String提供了如下方法 | 说明 |
String(byte[] bytes) | 通过使用平台的默认字符集解码指定的字节数组来构造新的String |
String(byte[] bytes, String charsetName) | 通过指定的字符集解码指定的字节数组来构造新的String |
public class demo {public static void main(String[] args) throws UnsupportedEncodingException {//编码String data = "a我b";byte[] bytes = data.getBytes(); //默认按照平台字符集(UTF-8)进行编码的System.out.println(Arrays.toString(bytes));//按照指定字符集编码byte[] bytes1 = data.getBytes("GBK");System.out.println(Arrays.toString(bytes1));//解码String s1 = new String(bytes); //默认按照平台字符集(UTF-8)进行解码System.out.println(s1); //a我bString s2 = new String(bytes1); //默认按照平台字符集(UTF-8)进行解码System.out.println(s2); //a��b 因为bytes1按照GBK解码,所以按照UTF-8解码会出现乱码String s3 = new String(bytes1,"GBK"); //指定字符集解码System.out.println(s3); //a我b}
}
四. IO流
IO流:输入输出流,用于读写数据
I指Input,称为输入流:负责把数据读到内存中去
O指Output,称为输出流:负责写数据出去
IO流的应用场景
IO流的分类
IO流总体来看就有四大流:字节输入流、字节输出流、字符输入流、字符输出流
4.1 FileInputStream(文件字节输入流)
· 作用:以内存为基准,可以把磁盘文件中的数据以字节的形式读入到内存中去
构造器 | 说明 |
public FileInputStream(File file) | 创建字节输入流管道与源文件接通 |
public FileInputStream(String pathname) | 创建字节输入流管道与源文件接通 |
方法名称 | 说明 |
public int read() | 每次读取一个字节返回,如果发现没有数据可读会返回-1 |
public int read(byte[] buffer) | 每次用一个字节数组去读取数据,返回字节数组读取了多少个字节,如果发现没有数据可读会返回-1 |
4.1.1 每次读取一个字节read()
· 使用FileInputStream的read()每次读取一个字节,读取性能较差,并且读取汉字输出会乱码
public class demo {public static void main(String[] args) throws Exception {//创建文件字节输入流管道,与源文件接通//public FileInputStream(File file) 创建字节输入流管道与源文件接通InputStream is = new FileInputStream(new File("demo/src/wosun.txt")); //多态//简化写法:推荐使用//public FileInputStream(String pathname) 创建字节输入流管道与源文件接通InputStream fis = new FileInputStream("demo\\src\\wosun.txt"); //多态//开始读取文件的字节数据//public int read() 每次读取一个字节返回,如果发现没有数据可读会返回-1
// 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(b3); //如果发现没有数据可读会返回-1//使用循环改造上述代码int b; //用于记住读取的字节while((b = fis.read()) != -1){System.out.print((char) b);}//上述方法一次只读一个字节,读取数据的性能很差(频繁调用系统资源)//上述方法一次只读一个字节,会导致读取汉字输入会乱码!无法避免!//流使用完毕之后,必须关闭!释放系统资源!fis.close();}
}
4.1.2 每次读取多个字节read(byte[] buffer)
· 使用FileInputStream的read(byte[] buffer)每次读取多个字节,读取性能得到提升,但读取汉字输出还是会乱码
public class demo {public static void main(String[] args) throws Exception {//创建一个字节输入流对象代表字节输入流管道与源文件接通InputStream fis = new FileInputStream("demo\\src\\wosun.txt"); //多态//开始读取文件的字节数据,每次读取多个字节// public int read(byte[] buffer)// 每次读取多个字节,用一个字节数组去读取数据,返回字节数组读取了多少个字节,如果发现没有数据可读会返回-1//byte[] buffer = new byte[1024]; //每次可以读1024个字节,即1KB
// byte[] buffer = new byte[3];
// int len1 = fis.read(buffer); //每次最多读3个字节
// String s1 = new String(buffer); //解码
// System.out.println(s1);
// System.out.println("当次读取的字节数:"+len1);
//
// //buffer = [abc]
// //buffer = [66c] //c没有覆盖,因此需要读取多少倒出多少
// int len2 = fis.read(buffer);
// //String s2 = new String(buffer); //66c
// String s2 = new String(buffer,0,len2); //66
// System.out.println(s2);
// System.out.println("当次读取的字节数:"+len2);
//
// int len3 = fis.read(buffer);
// System.out.println("当次读取的字节数:"+len3); //没有字节后读取的字节长度会是-1//优化byte[] buffer = new byte[3];int len; //记录每次读取了多少个字节while((len = fis.read(buffer)) != -1){String s = new String(buffer,0,len);System.out.println("当前读取到的字节:"+s+" 当前读取到的字节数:"+len);}fis.close();}
}
4.1.3 一次读取完全部字节
可以解决字节流读取中文输出乱码的问题,但是如果文件过大,创建的字节数组也会过大,可能引起内存溢出
一次读取完全部字节的两种方式
· 方式一:自己定义一个字节数组与被读取的文件大小一样大,然后使用该字节数组,一次读完文件的全部字节
· 方式二:Java官方为InputStream提供了如下方法,可以直接把文件的全部字节读取到一个字节数组中返回
public class demo {public static void main(String[] args) throws Exception {//创建一个文件对象File f = new File("demo\\src\\wosun.txt");//创建一个字节输入流对象代表字节输入流管道与源文件接通InputStream fis = new FileInputStream(f); //多态//方式1:自己定义一个字节数组与被读取的文件大小一样大,然后使用该字节数组,一次读完文件的全部字节
// //length:文件大小
// long length = f.length();
// //该方案只适合读相对来说较小的文件(不超过内存容量)
// byte[] buffer = new byte[(int) length];
//
// int len = fis.read(buffer); //len:当前读取到的字节数
// String s = new String(buffer,0,len);
// System.out.println("当前读取到的字节:"+s+" 当前读取到的字节数:"+len);//方式2:Java官方为InputStream提供了read方法,可以直接把文件的全部字节读取到一个字节数组中返回byte[] buffer = fis.readAllBytes(); //在jdk9中才出现的System.out.println(new String(buffer));fis.close();}
}
注意:
读写文本内容更适合用字符流;字节流适合做数据的转移,如文件复制等
4.2 FileOutputStream(文件字节输出流)
· 作用:以内存为基准,把内存中的数据以字节的形式写出到文件中去
构造器 | 说明 |
public FileOutputStream(File file) | 创建字节输出流管道与源文件对象接通 |
public FileOutputStream(String filepath) | 创建字节输出流管道与源文件路径接通 |
public FileOutputStream(File file, boolean append) | 创建字节输出流管道与源文件对象接通,可追加数据 |
public FileOutputStream(String filepath, boolean append) | 创建字节输出流管道与源文件路径接通,可追加数据 |
方法名称 | 说明 |
public void write(int a) | 写一个字节出去 |
public int write(byte[] buffer) | 写一个字节数组出去 |
public int write(byte[] buffer, int pos, int len) | 写一个字节数组的一部分出去 |
public void close() throws IOException | 关闭流 |
public class demo {public static void main(String[] args) throws Exception {//相对路径//以“./”开头,代表当前目录和文件目录在同一个目录里,“./”也可以省略不写!//以"../"开头:向上走一级,代表目标文件在当前文件所在的上一级目录;//以"../../"开头:向上走两级,代表父级的父级目录,也就是上上级目录,再说明白点,就是上一级目录的上一级目录//以"/”开头,代表根目录//创建一个字节输出流管道与目标文件接通//覆盖管道,会覆盖文件中原有的数据//OutputStream os = new FileOutputStream("demo/src/wosun.txt");//追加管道,不会覆盖文件中原有的数据OutputStream os = new FileOutputStream("demo/src/wosun.txt",true);//开始写字节数据出去//每次写一个字节os.write(97); //97就是一个字节,代表aos.write('b'); //'b'也是一个字节//os.write('你'); //乱码,因为write(int a)默认写一个字节,你在系统默认字符集(UTF-8)中占3个字节,因此乱码byte[] bytes = "abc你好星期天abc".getBytes();os.write(bytes);//换行os.write("\r\n".getBytes());os.write(bytes,3,15); //从3开始,写入15个字节,正好是“你好星期六”os.close(); //关闭流}
}
4.3 字节流案例:文件复制
字节流非常适合做一切文件的复制操作(任何文件的底层都是字节,字节流做副职,是一字不漏的转移完全部字节,只要复制后的文件格式一致就没有问题)
public class demo {public static void main(String[] args) throws Exception {//文件复制//需要创建一个字节输入流管道与原文件接通InputStream is = new FileInputStream("D:/zm/1.jpg");//创建一个字节输出流管道与目标位置接通OutputStream os = new FileOutputStream("D:/zm/aaa/1.jpg"); //要自己填写文件名//创建一个字节数组,负责转移字节数据byte[] buffer = new byte[1024]; //一次可以读取1KB//从字节输入流中读取字节数据,然后写到字节输出流中,读多少写多少//每次读取多个字节read(byte[] buffer)int len; //用来记录每次读取了多少字节while((len = is.read(buffer)) != -1){os.write(buffer,0,len);}//后创建的流先关闭,先创建的流后关闭os.close();is.close();System.out.println("复制完成");}
}//用try-catch-finally改良后的文件复制
public class demo {public static void main(String[] args) {InputStream is = null;OutputStream os = null;try {System.out.println(10/0); //出现异常//文件复制//需要创建一个字节输入流管道与原文件接通is = new FileInputStream("D:/zm/1.jpg");//创建一个字节输出流管道与目标位置接通os = new FileOutputStream("D:/zm/aaa/1.jpg"); //要自己填写文件名System.out.println(10/0); //出现异常//创建一个字节数组,负责转移字节数据byte[] buffer = new byte[1024]; //一次可以读取1KB//从字节输入流中读取字节数据,然后写到字节输出流中,读多少写多少//每次读取多个字节read(byte[] buffer)int len; //用来记录每次读取了多少字节while((len = is.read(buffer)) != -1){os.write(buffer,0,len);}System.out.println("复制完成");} catch (IOException e) {e.printStackTrace();} finally {//释放资源的操作try {if(os != null){os.close();}} catch (IOException e) {e.printStackTrace();}try {if(is != null){is.close();}} catch (IOException e) {e.printStackTrace();}}}
}
4.4 释放资源的方式
4.4.1 try-catch-finally
public class demo {public static void main(String[] args) throws Exception {try{System.out.println(10/2); //没有异常,也会执行finally中的代码// System.out.println(10/0); //出现异常,也会执行finally中的代码// return; //跳出方法的执行,也会执行finally中的代码// System.exit(0); //虚拟机jvm挂掉,就不会执行finally中的代码}catch (Exception e){e.printStackTrace();}finally {System.out.println("======finally执行了一次======");}System.out.println(chu(10, 2)); //111}public static int chu(int a,int b){try{return a/b;}catch (Exception e){e.printStackTrace();return -1;}finally {//千万不要在finally里返回数据return 111;}}
}
4.4.2 try-with-resource
public class demo {public static void main(String[] args) {//文件复制try(//需要创建一个字节输入流管道与原文件接通InputStream is = new FileInputStream("D:/zm/1.jpg");//创建一个字节输出流管道与目标位置接通OutputStream os = new FileOutputStream("D:/zm/aaa/1.jpg"); //要自己填写文件名//注意:这里只能放置资源对象(流对象)//什么是资源?// 资源都是会实现AutoCloseable接口,资源都会有一个close方法// 并且资源放到这里(try()里面)后,当它用完之后,会被自动调用其close方法完成资源的释放操作) {//创建一个字节数组,负责转移字节数据byte[] buffer = new byte[1024]; //一次可以读取1KB//从字节输入流中读取字节数据,然后写到字节输出流中,读多少写多少//每次读取多个字节read(byte[] buffer)int len; //用来记录每次读取了多少字节while((len = is.read(buffer)) != -1){os.write(buffer,0,len);}System.out.println("复制完成");} catch (IOException e) {e.printStackTrace();}}
}