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()); //0
System.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() 判断当前文件对象,对应的文件路径是否存在,存在返回true
System.out.println(f1.exists()); //true
System.out.println(f2.exists()); //false
//2.public boolean isFile() 判断当前文件对象指代的是否是文件,是文件返回true,反之false
System.out.println(f1.isFile()); //true
//3.public boolean isDirectory() 判断当前文件对象指代的是否是文件夹,是文件夹返回true,反之false
System.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,反之false
System.out.println(f1.createNewFile()); //不存在则创建成功,存在则创建失败
//2.public boolean mkdir() 用于创建文件夹,注意:只能创建一级文件夹
System.out.println(f2.mkdir()); //false
System.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
}
//· 当主调是文件,或者路径不存在时,返回null
File f2 = new File("D:/zm/1.txt"); //主调是文件
File[] files2 = f2.listFiles();
System.out.println(files2); //null
File 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我b
String 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就是一个字节,代表a
os.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();
}
}
}