Java基础 - 10 - File、IO流(一)

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();
        }
    }
}
  • 28
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值