File 类的用法和 InputStream, OutputStream 的用法(详解)

🎇🎉🎉🎉点进来你就是我的人了
博主主页:🙈🙈🙈戳一戳,欢迎大佬指点!
人生格言: 当你的才华撑不起你的野心的时候,你就应该静下心来学习!
欢迎志同道合的朋友一起加油喔 💪💪💪
目标梦想:进大厂,立志成为一个牛掰的Java程序猿,虽然现在还是一个🐒嘿嘿
谢谢你这么帅气美丽还给我点赞!比个心

1.File类

1.1File类对文件进行操作

package test;

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

public class Test01 {
    public static void main(String[] args) throws IOException {
        //将文件封装成一个 File 类对象
        //在windows,dos 中,系统默认用 “\”作为路径分隔符
        //在Unix/Linux 中,使用“/”作为路径分隔符
        File f = new File("d:\\test.txt");
        File f1 = new File("d:\\test.txt");
        File f2 = new File("d:/test.txt");

//        File.separator 属性帮我们获取当前操作系统的路径拼接符号
//        String separator = File.separator;
//        File.separator 是一个常量,用于表示文件路径分隔符,
//        它会根据当前操作系统自动选择合适的分隔符(在Windows系统中为 \,在Unix/Linux系统中为 /)。
        File f3 = new File("d:" + File.separator + "test.txt");

        System.out.println("文件是否可读:" + f.canRead());
        System.out.println("文件是否可写:" + f.canWrite());
        System.out.println("文件的名字:" + f.getName());
        System.out.println("文件的上级目录路径:" + f.getParent());
        System.out.println("是否是一个文件:" + f.isFile());
        System.out.println("是否是一个目录:" + f.isDirectory());
        System.out.println("文件是否隐藏:" + f.isHidden());
        System.out.println("文件的大小:" + f.length());
        System.out.println("文件是否存在:" + f.exists());

//        //对文件存在进行一个判断
//        if (f.exists()){//文件存在
//            //删除文件
//            f.delete();
//        }else {
//            //文件不存在,创建文件
//            f.createNewFile();//这里应该抛出一个 IO 异常
//        }
//        System.out.println(f == f1);//比较两个文件的地址(这种比较方法是错误的)
        //它比较的是对象的引用是否相同,即它们是否指向内存中的同一个对象。
        System.out.println("判断两个文件的地址是否一样:" + f.equals(f1));

        //接下来是与文件路径相关的
        System.out.println("绝对路径:" + f.getAbsolutePath());
        System.out.println("父目录文件路径:" + f.getParent());
        System.out.println("toString:" + f.toString());

        System.out.println("----------------------------------");

        File f4 = new File("./demo.txt");
        if (!f4.exists()){
            f4.createNewFile();
        }
        System.out.println("父目录文件路径:" + f4.getParent());
        //绝对路径:D:\2024\class-room-code\J20240714\demo.txt
        System.out.println("绝对路径:" + f4.getAbsolutePath());
        System.out.println("修饰过的绝对路径:" + f4.getCanonicalPath());
    }
}

1.2File类对目录进行操作

package test;

import java.io.File;

public class Test02 {
    public static void main(String[] args) {
        //将目录封装为File类的对象:
        File f = new File("D:/IDEA");
        System.out.println("文件是否可读:"+f.canRead());
        System.out.println("文件是否可写:"+f.canWrite());
        System.out.println("文件的名字:"+f.getName());
        System.out.println("上级目录:"+f.getParent());
        System.out.println("是否是一个目录:"+f.isDirectory());
        System.out.println("是否是一个文件:"+f.isFile());
        System.out.println("是否隐藏:"+f.isHidden());
        System.out.println("文件的大小:"+f.length());
        System.out.println("是否存在:"+f.exists());
        System.out.println("绝对路径:"+f.getAbsolutePath());
        System.out.println("相对路径:"+f.getPath());
        System.out.println("toString:"+f.toString());
        System.out.println("---------------------");
        //跟目录相关的方法:
        File f2 = new File("D:/b/b/c/c");
        File f3 = new File("D:\\c\\b\\c");
        //创建目录:
//        f2.mkdir();//创建单层目录
        f2.mkdirs();//创建多层目录
        //删除:如果是删除目录的话,只会删除一层,并且前提:这层目录是空的,里面没有内容,如果内容就不会被删除
        f2.delete();
        //查看:
        String[] list = f.list();//文件夹下目录/文件对应的名字的数组
        for(String s:list){
            System.out.println(s);  //只能输出文件名
        }
        System.out.println("=========================");
        File[] files = f.listFiles();//作用更加广泛
        for(File file:files) {
            //能通过对象去获取名字和路径等等
            System.out.println(file.getName() + "," + file.getAbsolutePath());
        }
    }
}

2.常用IO流

  • 所有流都实现了 Closeable 接口,都有close()方法,流用完要关闭。
  • 所有的输出流都实现了Flushable接口,都有flush()方法,flush()方法的作用是:将缓存清空,全部写出。养成好习惯,以防数据丢失。

在这里插入图片描述
在这里插入图片描述

  • 和File相关的IO流有四个分别是:
  • FileInputStream
  • FileOutputStream
  • FileReader
  • FileWriter
  • 其中FileReaderFileWriter为字符IO流
  • FileInputStreamFileOutputStream为字节IO流

3.读文件

3.1字节流–InputStream、FileInputStream 概述

  • InputStream 只是⼀个抽象类 ,要使⽤还需要具体的实现类。关于 InputStream 的实现类有很多 ,基本可以认为不同的输⼊设备都可以对应⼀个 InputStream 类 ,我们现在只关⼼从⽂件中读取 ,所以使⽤ FileInputStream
  • 文件字节输入流,可以读取任何文件

InputStream方法:

修饰符及返回值类型⽅法签名说明
intread()读取⼀个字节的数据 ,返回 -1 代表 已经完全读完了
intread(byte[] b)最多读取 b.length 字节的数据到 b 中 ,返回实际读到的数量;-1 代表 以及读完了
intread(byte[] b, int off, int len)最多读取 len - off 字节的数据到 b 中 ,放在从 off 开始 ,返回实际读 到的数量;-1 代表以及读完了
voidclose()关闭字节流

FileInputStream 构造方法:

  • 针对硬盘文件进行操作
签名说明
FileInputStream(File file)利⽤ File 构造⽂件输⼊流
FileInputStream(String name)利⽤⽂件路径构造⽂件输⼊流

📚打开文件

  • 如果打开成功,没有出现异常之类,接下来就可以读取文件内容了
InputStream inputStream = new FileInputStream("d:/test.txt")
  • 对于这一行代码,打开文件成功后,就得到了 InputStream 对象,后续针对文件的操作,就都是通过这个对象展开的。
  • 再者,我们操作硬盘不方便直接操作,在内存里构造一个和它关联的对象,操作这个对象就相当于操作硬盘数据。
  • 上述操作对象相当于操作硬盘数据,就类似于遥控器,我们开空调的时候,不可能每次借助梯子爬上去,用手摁下空调开关,而是通过空调遥控器去操作空调。

📚关闭文件

 inputStream.close();//非常关键的操作

为什么要关闭文件???

  • 关闭文件主要是为了释放文件描述符表资源。

文件描述符表,这个表就相当于是个数组,这个数组的下标就称为 “文件描述符”,每次打开一个文件,都会在文件描述符表中占据一个位置;每次关闭文件,都会释放一个位置。并且文件描述符表,是存在上线的,如果一个进程,一直在打开文件,没有释放,此时就会导致我们的进程在进行后续打开文件操作的时候,就会打开文件失败!!

📚读取文件

📄Read()实例

public static void main(String[] args) throws IOException {
        //打开文件
        InputStream inputStream = new FileInputStream("d:/test.txt");
        while (true){
            //一个字节一个字节进行读取
            int i = inputStream.read();
            if (i == -1){
                //读取完毕
                break;
            }
            System.out.printf("0x%x ", i);
        }
        //关闭文件
        inputStream.close();
    }

在这里插入图片描述
在这里插入图片描述

📄Read(byte[ ] b)实例

public static void main(String[] args) throws IOException {
        InputStream inputStream = new FileInputStream("d:/test.txt");
        while (true){
            byte[] bytes = new byte[1024];
            int n = inputStream.read(bytes);
            if (n == -1) {
                //读取完毕。n 就是 -1
                break;
            }
            for (int i = 0; i < n; i++) {
                System.out.printf("ox%x ",bytes[i]);
            }
        }
        inputStream.close();
    }

注意: 如果是读取中文,UTF8 的编码格式,一个汉字占3个字节。

如果要想读取中文在控制台,字节流只能通过指定编码格式,就比较麻烦。例如以下代码:

public static void main(String[] args) throws IOException {
        // 1.打开文件
        InputStream inputStream = new FileInputStream("d:/test.txt");
        // 2.读取文件
        byte[] buf = new byte[1024];
        int len = inputStream.read(buf);
        String s = new String(buf, 0, len, "UTF8");
        System.out.println(s);
        // 3.关闭文件
        inputStream.close();

    }

在这里插入图片描述

3.2字符流–Reader、FileReader

  • 和字节流方法差不多

📄Read(byte[ ] b)实例

public static void main(String[] args) throws IOException {
        // 字符流
        Reader reader = new FileReader("d:/test.txt");
        char[] buffer = new char[1024];
        int len = reader.read(buffer);
        for(int i = 0; i < len; i++) {
            System.out.println(buffer[i]);
        }
        reader.close();
    }

在这里插入图片描述

3.3利⽤ Scanner 进⾏字符读取

  • 上述例⼦中 ,我们看到了对字符类型直接使⽤ InputStream 进⾏读取是⾮常⿇烦且困难的,所以,我们使⽤⼀种我们之前⽐较熟悉的类来完成该⼯作 ,就是 Scanner 类。
构造⽅法说明
Scanner(InputStream is, String charset)使⽤ charset 字符集进⾏ is 的扫描读取
public static void main(String[] args) throws FileNotFoundException {
        InputStream inputStream = new FileInputStream("d:/test.txt");
        Scanner scanner = new Scanner(inputStream,"utf-8");
        while (scanner.hasNext()){
            String s = scanner.next();
            System.out.println(s);
        }
    }

在这里插入图片描述

3.4对关闭资源 close() 进行优化

  • 我们在前面字节流读取中文的代码中,发现如果在 read() 读文件的过程中出现异常,就可能导致 close() 执行不到,按照我们以前的思路,使用 try…catch…finally,将关闭资源放在 finally 中。
    public static void main(String[] args) {
        InputStream inputStream = null;
        try {
            // 打开文件(字节流)
            inputStream = new FileInputStream("d:/test.txt");
            byte[] buf = new byte[1024];
            int len = inputStream.read(buf);
            // 读取中文
            String s = new String(buf, 0, len, "UTF8");
            System.out.println(s);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
  • 更推荐的做法是以下做法:
    public static void main(String[] args) {
        try (InputStream inputStream = new FileInputStream("d:/test.txt")) {
 
            byte[] buf = new byte[1024];
            int len = inputStream.read(buf);
            // .........
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

注意:创建对象写在 try 后面的 括号里面

4.写文件

4.1字节流 – OutputStream、 FileOutputStream概述

OutputStream方法:

修饰符及返回值类型⽅法签名说明
voidwrite(intb)写⼊要给字节的数据
voidwrite(byte[] b)将 b 这个字符数组中的数据全部写 ⼊ os 中
intwrite(byte[] b, intoff, int len)将 b 这个字符数组中从 off 开始的 数据写⼊ os 中 ,⼀共写 len 个
voidclose()关闭字节流
voidflush()重要:我们知道 I/O 的速度是很慢 的 ,所以 ,⼤多的 OutputStream 为了减少设备操作的次数 ,在写数 据的时候都会将数据先暂时写⼊内 存的⼀个指定区域⾥ ,直到该区域 满了或者其他指定条件时才真正将 数据写⼊设备中 ,这个区域⼀般称 为缓冲区。但造成⼀个结果 ,就是 我们写的数据 ,很可能会遗留⼀部 分在缓冲区中。需要在最后或者合 适的位置 ,调⽤ flush(刷新)操 作 ,将数据刷到设备中。
  • OutputStream 同样只是⼀个抽象类 ,要使⽤还需要具体的实现类。我们现在还是只关⼼写⼊⽂件 中 ,所以使⽤ FileOutputStream

📚利⽤ OutputStream Writer 进⾏字符写⼊

public static void main(String[] args) throws IOException {
        try (OutputStream outputStream = new FileOutputStream("d:/test.txt")){
            outputStream.write('H');
            outputStream.write('e');
            outputStream.write('l');
            outputStream.write('l');
            outputStream.write('o');
            outputStream.flush();
        }
    }
public static void main(String[] args) throws IOException {
        try (OutputStream outputStream = new FileOutputStream("d:/test.txt")){
            byte[] bytes = new byte[]{
                    (byte) 'G',(byte) 'o',(byte) 'o',(byte) 'd'
            };
            outputStream.write(bytes);
            outputStream.flush();
        }
    }
  • 注意:以上两个代码案例
    每次重新写的时候,都会把旧的文件内容清空掉,重新去写。
    但是这种原生字节流的写文件方法,用起来还是不方便。

4.2字符流 – Writer、FileWriter

  • 代码示例
    public static void main(String[] args) {
        try (Writer writer = new FileWriter("d:/test.txt")) {
            // 能写字符串,就很方便
            writer.write("hello world");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • 我们的这个字符流中的 Writer 还能写字符串,就很方便。还有一种方式 – PrintWriter ,它提供了更丰富的写。

📚利⽤ PrintWriter 找到我们熟悉的⽅法

  • 上述 ,我们其实已经完成输出⼯作 ,但总是有所不⽅便 ,我们接来下将 OutputStream 处理下 ,使⽤ PrintWriter 类来完成输出 ,因为PrintWriter 类中提供了我们熟悉的 print/println/printf ⽅法
public static <outputStreamWriter> void main(String[] args) throws IOException {
        try (OutputStream outputStream = new FileOutputStream("d:/test.txt");
             OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream,"utf-8");
             PrintWriter printWriter = new PrintWriter(outputStreamWriter)) {
            printWriter.println("我是第一行");
            printWriter.print("我的第⼆⾏\r\n");
            printWriter.printf("%d: 我的第三⾏\r\n", 1 + 1);
            printWriter.flush();
        }
    }

在这里插入图片描述

5.try-with-resources

  • try-with-resources是Java 7中引入的一个特性,它是为了简化在程序中使用资源(例如文件、网络连接等)的管理。在Java程序中,资源的正确关闭非常重要,因为资源泄漏可能导致性能问题、程序错误或其他问题。try-with-resources语句确保在代码块执行完毕后自动关闭资源,无论代码执行过程中是否发生异常。

  • try-with-resources语句实现自动关闭资源的方式是通过在资源实现java.lang.AutoCloseable或java.io.Closeable接口的情况下,确保close()方法被调用。这两个接口都包含一个close()方法,它们的实现负责释放资源。

5.1try-with-resources 代码案例

public static void main(String[] args) throws IOException {
        try (InputStream inputStream = new FileInputStream("d:/test.txt")){
            while (true){
                byte[] bytes = new byte[1024];
                int n = inputStream.read(bytes);
                if (n == -1) {
                    //读取完毕。n 就是 -1
                    break;
                }
                for (int i = 0; i < n; i++) {
                    System.out.printf("ox%x ",bytes[i]);
                }
            }

        }
    }

注意:创建对象写在 try 后面的 括号里面

当程序执行到try语句块结束时,如果resource实现了AutoCloseable或Closeable接口,那么close()方法将被自动调用。这确保了无论try块中是否抛出异常,资源都会被正确关闭。
因此,try-with-resources语句可以自动关闭资源,主要是因为它依赖实现AutoCloseable或Closeable接口的资源,使得在try语句块结束时自动调用close()方法。这简化了资源管理,降低了资源泄漏和相关问题的风险。
注意:如果一个资源没有实现AutoCloseable或Closeable接口,那么try-with-resources语句将无法自动关闭该资源。在这种情况下,你需要在代码中手动管理资源的关闭。

  • 40
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值