Day15-【Java SE进阶】IO流(一):File、IO流概述、File文件对象的创建、字节输入输出流FileInputStream FileoutputStream、释放资源。

一、 File和IO流

  • File是java.io包下的类, File类的对象,用于代表当前操作系统的文件(可以是文件、或文件夹)
  • 注意:File类只能对文件本身进行操作,不能读写文件里面存储的数据

IO流

  • 用于读写数据的(可以读写文件,或网络中的数据…)

1. 创建对象

在这里插入图片描述

  • File对象既可以代表文件、也可以代表文件夹。
  • File封装的对象仅仅是一个路径名,这个路径可以是存在的,也允许是不存在的。
package com.file;

import java.io.File;

public class FileTest {
    public static void main(String[] args) {
        //1.创建一个file对象,指代某个具体的文件 路径使用/或者\\
        //File file = new File("E:\\Desktop\\Two\\日期\\202402\\Java\\workspace\\JavaStudy\\day07\\src\\com\\file\\test.txt");
        //File file = new File("E:/Desktop/Two/日期/202402/Java/workspace/JavaStudy/day07/src/com/file/test.txt");
        File file = new File("E:/Desktop/Two/日期/202402/Java/workspace/JavaStudy/day07/src/com/file/test.txt");
        //File file1 = new File("D:" + File.separator + "resource" + File.separator + "ab.txt");
        System.out.println(file.length());//文件大小
        //可以指代一个文件夹,但是大小仅仅为文件夹本身的大小
        File file1 = new File("C:\\Users\\13492\\Desktop\\dir");
        System.out.println(file1.length());
        //File对象可以指代一个不存在的文件路径
        File file2 = new File("C:\\Users\\13492\\Desktop\\dir");
        System.out.println(file2.exists());
        System.out.println(file2.length());

        //绝对路径不推荐,带盘符,相对路径不带盘符,此处的相对路径时相对于工程目录,即idea打开的项目的路径
        File file3 = new File("JavaStudy/day07/src/com/file/test.txt");
        System.out.println(file3.length());
    }
}

2. 常用方法

判断文件类型、获取文件信息
在这里插入图片描述

package com.file;

import java.io.File;
import java.text.SimpleDateFormat;

public class FileTest1 {
    public static void main(String[] args) {
        //1.创建文件对象,代替某个文件
        File file = new File("day07/src/com/file/test.txt");
        //2.public boolean exists():判断当前文件对象,对应的文件路径是否存在,存在返回true.
        System.out.println(file.exists());
        //3、public boolean isFile():判断当前文件对象指代的是否是文件,是文件返回true,反之。
        System.out.println(file.isFile());
        //4、public boolean isDirectory) :判断当前文件对象指代的是否是文件夹,是文件夹返回true,反之。
        System.out.println(file.isDirectory());
        //5.public String getName():获取文件的名称(包含后缀)
        System.out.println(file.getName());
        // 6.public long length():获取文件的大小,返回字节个数
        System.out.println(file.length());
        // 7.public long lastHodified():获取文件的最后修改时间。
        long l = file.lastModified();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(sdf.format(l));
        // 8.public String getPath():获取创建文件对象时,使用的路径
        System.out.println(file.getPath());
        // 9.public String getAbsolutePath():获取绝对路径
        System.out.println(file.getAbsoluteFile());
    }
}

创建文件、删除文件

        // 1、public boolean createNewFile():创建一个新文件(文件内容为空),创建成功返回true,反之。
        File file1 = new File("day07/src/com/file/test1.txt");
        System.out.println(file1.createNewFile());
        // 2、public boolean mkdir():用于创建文件夫,注意:只能创建一级文件夹
        File file2 = new File("day07/src/com/file/test");
        System.out.println(file2.mkdir());
        // 3、public boolean mkdirs():用于创建文件夹,注意:可以创建多级文件夹
        File file3 = new File("day07/src/com/file/test/test/test");
        System.out.println(file3.mkdirs());
        // 4、public boolean delete():删除文件,或者空文件,注意:不能删除非空文件夹。
        File file4 = new File("day07/src/com/file/test/test/test");
        System.out.println(file4.delete());

在这里插入图片描述
遍历文件夹

package com.file;

import java.io.File;
import java.util.Arrays;

public class FileTest2 {
    public static void main(String[] args) {
        //1、 public String[] list()获取当前目录下所有的一级文件名称到一个字符串数组中去返回。
        File file = new File("day07/src/com/file/test/test");
        System.out.println(Arrays.toString(file.list()));
        //2、public File[]listFiles():(爾点)获取当前目录下所有的"一级文件对象"到一个文件对象数组中去返回(点)
        File file1 = new File("day07/src/com/file/test/test");
        File[] files = file1.listFiles();
        System.out.println(Arrays.toString(files));
    }
}

在这里插入图片描述
使用listFiles方法时的注意事项:

  • 当主调是文件,或者路径不存在时,返回null
  • 当主调是空文件夹时,返回一个长度为0的数组
  • 当主调是一个有内容的文件夹时,将里面所有一级文件和文件夹的路径放在File数组中返回
  • 当主调是一个文件夹,且里面有隐藏文件时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
  • 当主调是一个文件夹,但是没有权限访问该文件夹时,返回null

3. 方法递归

  • 递归是一种算法,在程序设计语言中广泛应用
  • 从形式上说:方法调用自身的形式称为方法递归(recursion)
  • 直接递归:方法自己调用自己。
  • 间接递归:方法调用其他方法,其他方法又回调方法自己
  • 递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出错误。
    在这里插入图片描述
package com.file;

public class Recursion {
    public static void main(String[] args) {
        System.out.println(test1(6));
        System.out.println(eatPeach(1));
    }

    public static int test1(int a) {
        if(a==1) return 1;
        return a*test1(a-1);
    }
    public static int eatPeach(int n){
        if(n==10) return 1;
        return (eatPeach(n+1)+1)*2;
    }
}

递归算法的三要素

  • 递归的公式:f(n)= f(n-1)*n;
  • 递归的终结点:f(1)
  • 递归的方向必须走向终结点:

文件搜索

package com.file;

import java.io.File;
import java.io.IOException;

public class FileTest4 {
    public static void main(String[] args) throws IOException {
//        File file = new File("day07/src/com/file/test/test");
//        System.out.println(Arrays.toString(file.listFiles()));
//        String s= "day07\\src\\com\\file\\test\\test\\test.txt";
//        System.out.println(Arrays.toString(s.split("\\\\")));
        findFile(new File("E:\\InstalledSoftware"), "douyin.exe");
    }

    /**
     * 去目录下搜索某个文件
     *
     * @param dir 目录
     * @param f   要搜索的文件名称
     * @return
     */
    public static void findFile(File dir, String f) throws IOException {
        //1.把非法的情况都拦截住
        if (dir == null || !dir.exists()) return;
        //2.dir不是null,存在,一定是目录对象。
        // 获取当前目录下的全部一级文件对象
        File[] files = dir.listFiles();
        //3.判断当前目录下是否存在一级文件对象,以及是否可以拿到一级文件对象
        if (files != null) {
            for (File file : files) {
                if (file.isFile() && file.getName().contains(f)) {
                    System.out.println(file.getAbsolutePath());
                    Runtime runtime = Runtime.getRuntime();
                    runtime.exec(file.getAbsolutePath());
                } else {
                    findFile(file, f);
                }
            }
        }
    }
}

4. 字符集

  • ASClI(American standard Code for Information Interchange): 美国信息交换标准代码,包括了英文、符号等。
  • 标准ASCI使用1个字节存储一个字符 首尾是0 总共可表示128个字符,对美国佬来说完全够用。

GBK(汉字内码扩展规范,国标)

  • 汉字编码字符集,包含了2万多个汉字等字符 GBK中一个中文字符编码成两个字节的形式存储

  • 注意:GBK兼容了ASCII字符集。

  • GBK规定:汉字的第一个字节的第一位必须是1
    在这里插入图片描述
    Unicode字符集(统一码,也叫万国码)

  • Unicode是国际组织制定的,可以容纳世界上所有文字、符号的字符集。

  • UTF-32有容乃大我4个字节表示一个字符 奢份!占存储空间,通信效率变低!

  • UTF-8是Unicode字符集的一种编码方案,采取可变长编码方案,共分四个长度区:1个字节,2个字节,3个字节,4个字节

    • 英文字符、数字等只占1个字节(兼容标准ASCII编码),汉字字符占用3个字节
      在这里插入图片描述
    • 注意:技术人员在开发时都应该使用UTF-8编码!
  • ASCII字符集:只有英文、数字、符号等,占1个字节

  • GBK字符集:汉字占2个字节,英文、数字占1个字节

  • UTF-8字符集:汉字占3个字节,英文、数字占1个字节

  • 注意1:字符编码时使用的字符集,和解码时使用的字符集必须一致,否则会出现乱码

  • 注意2:英文,数字一般不会乱码,因为很多字符集都兼容了ASCII编码

字符集的编码、解码操作
编码:把字符按照指定字符集编码成字节。
解码:把字节按照指定字符集解码成字符。
Java代码完成对字符的编码
在这里插入图片描述
Java代码完成对字符的解码
在这里插入图片描述

import java.io.UnsupportedEncodingException;
import java.util.Arrays;

public class FileTest5 {
    public static void main(String[] args) throws UnsupportedEncodingException {
        //1.encode
        String data = "a我b";
        byte[] bytes = data.getBytes();//默认是按照平台字符集进行编码的。
        System.out.println(Arrays.toString(bytes));

        //按照指定字符集进行编码
        byte[] bytes1 = data.getBytes("GBK");
        System.out.println(Arrays.toString(bytes1));

        //2. decode
        String s = new String(bytes);//按照平台默认编码解码
        System.out.println(s);

        String s1 = new String(bytes1,"GBK");
        System.out.println(s1);
    }
}

5. IO流


在这里插入图片描述

  • 字节输入流:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流
  • 字节输出流:以内存为基准,把内存中的数据以字节写出到磁盘文件或者网络中去的流
  • 字符输入流:以内存为基准,来自磁盘文件/网络中的数据以字符的形式读入到内存中去的流
  • 字符输出流:以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络介质中去的流

在这里插入图片描述
文件字节输入流:每次读取一个字节

文件字节输入流:每次读取多个字节

文件字节输入流:一次读取完全部字节

文件字节输出流:写字节出去

5.1 FileInputStream(文件字节输入流)

作用:以内存为基准,可以把磁盘文件中的数据以字节的形式读入到内存中去。
在这里插入图片描述

package com.file;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class FileTest6 {
    public static void main(String[] args) throws IOException {
        File file = new File("day07/src/com/file/test.txt");
        //创建文件字节输入流管道,与源文件接通
        InputStream fileInputStream = new FileInputStream(file);
        //简化写法,推荐使用
        FileInputStream fileInputStream1 = new FileInputStream("day07/src/com/file/test.txt");
        //开始读取文件的字节数据
        //每次读取一个字节返回,如果没有数据了,返回-1
//        System.out.println((char) fileInputStream.read());
//        System.out.println((char) fileInputStream.read());
        //使用循环改造上述代码
        //读取数据的性能很差
        //读取汉字输出会乱码且无法避免的
        //流使用完毕之后,必须关闭!释放系统资源!
        int i;
        while ((i = fileInputStream1.read()) !=- 1){
            System.out.print((char)i);
        }
        fileInputStream.close();
        fileInputStream1.close();
    }
}

文件字节输入流:每次读取多个字节到字节数组中去,返回读取的字节数量,读取完毕会返回-1

package com.file;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class FileTest7 {
    public static void main(String[] args) throws IOException {
        //1.创建一个字节输入流对象代表字节输入流管道与源文件接通
        InputStream is = new FileInputStream("day07/src/com/file/test.txt");
        //2.开始读取文件中的字节数据,每次读取多个字节
        byte[] bytes = new byte[3];
        int read = is.read(bytes);
        String s = new String(bytes,0,read);
        System.out.println(s);
        System.out.println("当次读取的字节个数:"+read);

        int read1 = is.read(bytes);
        //注意:读取多少,倒出多少
        String s1 = new String(bytes,0,read1);
        System.out.println(s1);
        System.out.println("当次读取的字节个数:"+read1);
        //3、使用循环改造 一次读取多个字节 程序性能大幅提升 系统调用次数减少 也不能避免读取汉字会出现乱码的问题
        byte[] bytes1 = new byte[3];
        int len;
        while ((len=is.read(bytes1))!=-1){
            String s2 = new String(bytes1, 0, len);
            System.out.print(s2);
        }
        is.close();
    }
}

注意事项:使用FileInputStream每次读取多个字节,读取性能得到了提升,但读取汉字输出还是会乱码
1、使用字节流读取中文,如何保证输出不乱码,怎么解决?
定义一个与文件一样大的字节数组,一次性读取完文件的全部字节。
文件字符输入流:一次读取完全部字节 可以解决中文读取乱码的问题

  • 方式一:自己定义一个字节数组与被读取的文件大小一样大,然后使用该字节数组,一次读完文件的全部字节。
  • 在这里插入图片描述
  • 方式二:java官方为InputStream提供了如下方法,可以直接把文件的全部字节读取到一个字节数组中返回。
  • 在这里插入图片描述
package com.file;

import java.io.*;

public class FileTest8 {
    public static void main(String[] args) throws IOException {
        //1、一次性读取完文件的全部字节到一个字节数组中去。
        // 创建一个字节给入流管道与源文件接通
        InputStream is = new FileInputStream("day07/src/com/file/test.txt");
        //2、准备一个字节数姐,大小与文件的大小正好一样大。
        File file = new File("day07/src/com/file/test.txt");
        long length = file.length();
        byte[] bytes = new byte[(int) length];
        int read = is.read(bytes);
        String s = new String(bytes);
        System.out.println(s);
        System.out.println(read);
        //3、需要注释第二部分代码
        byte[] bytes1 = is.readAllBytes();
        String s1 = new String(bytes1);
        System.out.println(s1);
    }
}

1、直接把文件数据全部读取到一个字节数组可以避免乱码,是否存在问题?

  • 如果文件过大,创建的字节数组也会过大,可能引起内存溢出。
  • 读写文本内容更适合用字符流
  • 字节流 适合做数据的转移,如:文件复制等
5.2 FileOutputStream(文件字节输出流)

作用:以内存为基准,把内存中的数据以字节的形式写出到文件中去
在这里插入图片描述

在这里插入图片描述

package com.file;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class FileTest9 {
    public static void main(String[] args) throws IOException {
        //1、创建一个字节输出流管道与目标文件接通
        //覆盖管道:覆盖之前的数据
//        OutputStream fileOutputStream = new FileOutputStream("day07/src/com/file/out.txt");
        //追加数据的管道
        OutputStream fileOutputStream = new FileOutputStream("day07/src/com/file/out.txt",true);
        //2、开始写字节数据出去
        fileOutputStream.write(97);
        fileOutputStream.write('b');
        //fileOutputStream.write('是');
        byte[] bytes = "我爱你中国abc!".getBytes();
        fileOutputStream.write(bytes);
        fileOutputStream.write(bytes,0,15);
        fileOutputStream.write("\r\n".getBytes());//换行,支持各个平台的换行\r\n
        fileOutputStream.close();

    }
}

复制文件:可以复制一切文件的

  • 字节流非常适合做一切文件的复制操作
  • 任何文件的底层都是字节,字节流做复制,是一字不漏的转移完全部字节,只要复制后的文件格式一致就没问题!
package com.file;

import java.io.*;

public class FileTest10 {
    public static void main(String[] args) throws IOException {
        //需求:复制图片
        //1、创建一个字节给入流价道与源文件接通
        InputStream is = new FileInputStream("day07/src/com/file/test/49.jpg");
        //2、创建一个字节给出流管道与目标文件接通。
        OutputStream out = new FileOutputStream("day07/src/com/file/test/50.jpg");
        //3、创建一个字节数组,负责转移字节数据。
        byte[] bytes = new byte[1024];
        //4、从字节输入流中读取字节数据,写出去到字节输出流中。读多少写出去多少。
        int len;
        while ((len=is.read(bytes))!=-1){
            out.write(bytes,0,len);
        }
        //后创建的流先关掉 注意 可以避免一定问题的
        out.close();
        is.close();
    }
}

5.3 释放资源的方式

中间出异常时,close方法无法被触发,无法释放资源。
try-catch-finally臃肿

  • finally代码区的特点:无论try中的程序是正常执行了,还是出现了异常,最后都一定会执行finally区,除非JVM终止。
  • 作用:一般用于在程序执行完成后进行资源的释放操作(专业级做法)。
package com.file;

public class FileTest11 {
    public static void main(String[] args) {
        try {
            System.out.println(10/2);
            System.out.println(chu(1, 2));
//            Runtime runtime = Runtime.getRuntime();
//            runtime.exit(0);
            return;
        }catch (Exception e){
            e.printStackTrace();
        }
//        System.out.println("===执行了一次===");
        finally {
            System.out.println("===finally执行了一次===");
        }
    }
    public static int chu(int a, int b){
        try {
            return a/b;
        }catch (Exception e){
            e.printStackTrace();
            return -1;
        }finally {//千万不要再finally中return数据
            return 111;
        }
    }
}

package com.file;

import java.io.*;

public class FileTest10 {
    public static void main(String[] args) throws IOException {
        InputStream is = null;
        OutputStream out = null;
        try {
            //需求:复制图片
            //1、创建一个字节给入流价道与源文件接通
            is = new FileInputStream("day07/src/com/file/test/49.jpg");
            //2、创建一个字节给出流管道与目标文件接通。
            out = new FileOutputStream("day07/src/com/file/test/50.jpg");
            //3、创建一个字节数组,负责转移字节数据。
            byte[] bytes = new byte[1024];
            //4、从字节输入流中读取字节数据,写出去到字节输出流中。读多少写出去多少。
            int len;
            while ((len = is.read(bytes)) != -1) {
                out.write(bytes, 0, len);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //后创建的流先关掉 注意 可以避免一定问题的
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

try-with-resource推荐

  • 该资源使用完毕后,会自动调用其close()方法,完成对资源的释放!
    在这里插入图片描述
package com.file;

import java.io.*;

public class FileTest10 {
    public static void main(String[] args) throws IOException {
        try (//注意:这里只能放置资源对象。(流对象)
             //资源都是会实现一个AutoCloseable接口的
                //需求:复制图片
                //1、创建一个字节给入流价道与源文件接通
                InputStream is = new FileInputStream("day07/src/com/file/test/49.jpg");
                //2、创建一个字节给出流管道与目标文件接通。
                OutputStream out = new FileOutputStream("day07/src/com/file/test/50.jpg");
        ) {
            //3、创建一个字节数组,负责转移字节数据。
            byte[] bytes = new byte[1024];
            //4、从字节输入流中读取字节数据,写出去到字节输出流中。读多少写出去多少。
            int len;
            while ((len = is.read(bytes)) != -1) {
                out.write(bytes, 0, len);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jingwei1205

宝贝儿 施舍施舍吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值