文件操作IO


一、认识文件

文件,File这个词,在计算机中也是 “一词多义”。
狭义的文件:指的是电脑上的文件和目录。
广义的文件:泛指计算机中很多的软硬件资源,操作系统中,把很多的硬件设备和软件资源抽象成了文件,按照文件方式来统一管理。后面讲到网络编程,操作系统也把网卡当成一个文件。
咱们本章节,只讨论狭义的文件。

二、文件路径

之前咱们写代码中,存储数据,主要是内存,变量存在内存中。现在我们讨论的文件是在硬盘上。
每个文件,在硬盘上都有一个具体的路径:D:/file.txt。
表示一个文件具体的位置路径,就可以使用 / 来分割不同的目录级别。


在计算机中,路径又分为绝对路径和相对路径。

2.1 绝对路径

绝对路径以 C:、D:、E:盘符开头的路径。
在这里插入图片描述

2.2 相对路径

相对路径,是以当前的路径作为基准,找到执行的路径。
当前所在的目录称为工作目录,每个程序运行的时候,都有一个工作目录,在控制台里通过命令来操作特别明显,后来图形化界面,工作目录就没那么明显了。

三、文件类型

文件类型有:word、exe、图片、视频、音频、源代码、动态库…
这些不同的文件,整体可以归纳为两类:

3.1.文本文件

存放的是文本、字符串。
字符串是由字符构成的,每个字符都是通过一个数字磊表示的,这个文本文件里存的数据一定是合法的字符,都是指定字符编码表之内的字数据。

3.2.二进制文件

存的是二进制文件,不一定是字符串。没有任何限制,可以存储你任何想要的数据。


注意!! 如何区分一个文件是文本文件还是二进制文件?
可以通过记事本打开,没有乱码的就是文本文件,如果乱码了,就是二进制文件。

四、文件操作

4.1 文件系统操作

文件操作系统包括:文件创建、文件删除、文件重命名…
Java 标准库里提供了一个 File 类。

4.1.1 属性

pathSeparator:File 里的一个静态变量,就是 / 或者 ./ ,跟着系统走的。

4.1.2 构造方法

File(File parent, String child):根据父目录 + 孩子文件路径,创建一个新的 File 实例。
File(String pathname):根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者相对路径。
File(String parent, String child):根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用路径表示。

在 new File 的时候,构造方法中指定一个路径,此时这个 File 对象就代表这个路径所对应的文件。

4.1.3 方法

1.getName:获取到文件名字。

    public static void main(String[] args) {
        File file = new File("D:/czy.txt");
        String fileName = file.getName();
        System.out.println(fileName);
    }

在这里插入图片描述
2.getPardent:得到父目录路径

 public static void main(String[] args) {
        File file = new File("D:/czy.txt");
        String filePar = file.getParent();
        System.out.println(filePar);
    }

在这里插入图片描述
3. getPath:得到文件路径

    public static void main(String[] args) {
        File file = new File("D:/czy.txt");
        String filePath = file.getPath();
        System.out.println(filePath);
    }

在这里插入图片描述
4.getAbsolutePath:得到文件的就对路径

    public static void main(String[] args) {
        File file = new File("D:/czy.txt");
        String filePath = file.getAbsolutePath();
        System.out.println(filePath);
    }

在这里插入图片描述

  1. getCanonicaPath:得到文件修饰过的路径
public static void main(String[] args) throws IOException {
        File file = new File("D:/czy.txt");
        String filePath = file.getCanonicalPath();
        System.out.println(filePath);
    }

在这里插入图片描述

  1. exits:查看文件是否存在
    public static void main(String[] args) throws IOException {
        File file = new File("D:/czy.txt");
        boolean ret = file.exists();
        System.out.println(ret);
    }

在这里插入图片描述

  1. isDirectory:查看File对象是否为目录
    public static void main(String[] args) throws IOException {
        File file = new File("D:/czy.txt");
        boolean ret = file.isDirectory();
        System.out.println(ret);
    }

在这里插入图片描述
7. isFile:查看当前File对象是否为文件

    public static void main(String[] args) throws IOException {
        File file = new File("D:/czy.txt");
        boolean ret = file.isFile();
        System.out.println(ret);
    }

在这里插入图片描述
8.createNewFile:创建一个新文件

 public static void main(String[] args) throws IOException {
        File file = new File("D:/czy.txt");
        boolean ret = file.createNewFile();
        System.out.println(ret);
    }

在这里插入图片描述
9.delete:删除文件

public static void main(String[] args) throws IOException {
        File file = new File("D:/czy.txt");
        boolean ret = file.delete();
        System.out.println(ret);
    }

在这里插入图片描述

10.list:查看File对象代表的目录下所有文件名

public static void main(String[] args) throws IOException {
        File file = new File("D:/360压缩");
        String[] ret = file.list();

        for (int i = 0; i < ret.length; i++) {
            System.out.println(ret[i]);
        }
    }

在这里插入图片描述
11.listFile:

    public static void main(String[] args) throws IOException {
        File file = new File("D:/360压缩");
        File[] ret = file.listFiles();

        for (int i = 0; i < ret.length; i++) {
            System.out.println(ret[i]);
        }
    }

在这里插入图片描述
12.mkdir:创建目录
不会创建中间目录

    public static void main(String[] args) throws IOException {
        File file = new File("D:/czy");
        boolean ret = file.mkdirs();
        System.out.println(ret);
    }

在这里插入图片描述
如果想要创建中间目录,使用 mkdirs。

4.2 文件内容的读写–数据流

针对文件内容,我们使用 “流对象” 进行操作。
Java 标准库里的流对象,从类型上,分为两类:
1.字节流
2.字符流

4.2.1 字节流

操作字节的。常见的类有:InputStream、OutputStream、FileInputStream、FileOutputStream。

4.2.1.1 read

1.无参版本 read()
一次读取一个字节。
例如读取 czy.txt 文件。
在这里插入图片描述

    public static void main(String[] args) throws FileNotFoundException {
        InputStream inputStream = new FileInputStream("D:/czy.txt");
        try {
            while (true) {
                int ret = inputStream.read();
                System.out.println(ret);
                if(ret == -1) {
                    return;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述

2.一个参数版本 read(byte[] buffer)
把读到的内容输入到字节数组 buffer 中,此处的参数是个 “输出型参数”,返回值是实际读取到的字节数。

public static void main(String[] args) throws FileNotFoundException {
        InputStream inputStream = new FileInputStream("D:/czy.txt");
        byte[] buffer = new byte[1024];

        while (true) {
            int ret = 0;
            try {
                ret = inputStream.read(buffer);
                System.out.println("ret=" + ret);
                if(ret == -1) {
                    return;
                }

                for (int i = 0; i < ret; i++) {
                    System.out.println(buffer[i]);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


注意理解read的行为和返回值。

read会尽可能把传进来的数组参数填满,上面给的数组大小为1024,read 会尽可能读取1024个字节的数据,填到数组中,如果当前文件大小小于1024,全部读取,返回读取的长度;如果读取的文件超过1024,就读取1024,并返回1024。


很显然,上面的文件时文本文件,可以通过字节流去读,但是不方便我们去观察,更希望的是通过一个字符一个字符去读,所以引出了下面的字符流读取文件。

4.2.1.1 write

使用OutputStream 类来完成,对于 OutputStream 来说,默认情况下,打开一个文件,会先清空文件原有内容。
1.无参数版本: write()
原来文件内容:
在这里插入图片描述

    public static void main(String[] args) throws IOException {
        OutputStream outputStream = new FileOutputStream("D:/czy.txt");
        outputStream.write(97);
        outputStream.write(98);
        outputStream.write(99);
    }

现在文件内容:
在这里插入图片描述
另外OutputStream 打开文件,记得要关闭文件。

outputStream.close();

前面,我们说到,操作系统里,我们用PCB数据结构表示一个线程,一个进程里有多个线程,PCB有个重要的属性,文件描述符表,一个进程中的多个线程共用这一个文件描述符表。
在这里插入图片描述
每次打开一个文件,就会在文件描述符表上占一个位置,把这个信息放进去,每次关闭文件也会把这个文件描述符表对应的表项释放掉。
那么问题来了,如果没有close,对应的表项就不会释放,虽然Java有GC,但是GC操作会在回收OutputStream 的时候回收这个表项,不一定做到及时回收。所以,如果不及时释放,意味着文件描述符很快就占满了,而这个文件描述符表是不能自动扩容的。当再次打开文件,就会打开失败。


那么,如何才能保证close操作一定能被执行到呢?
最推荐的写法如下:

    public static void main(String[] args) throws FileNotFoundException {
        try ( OutputStream outputStream = new FileOutputStream("D:/czy.txt");){
            outputStream.write(97);
            outputStream.write(98);
            outputStream.write(99);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

这个写法虽然没有显示的写close,实际上是会执行,只要try语句执行完毕,就会自动执行close。这个语法在Java中称为 “try with resources”。

注意!!
不是随便拿个对象放在try里都能够自动释放,必须满足一定要求。
要求:必须实现了 Closeable 接口的类,才能放到 try 中,close 才自动关闭。

public abstract class OutputStream implements Closeable, Flushable

4.2.2 字符流

操作文本数据的。常见的类有:Reader、Writer、FileReader、FileWriter。
字符流和字节流用法差不多。

4.2.2.1 read

1.无参版本

    public static void main(String[] args) {

        try (Reader reader = new FileReader("D:/czy.txt");){
            while (true) {
                int ret = reader.read();
                if(ret == -1) {
                    break;
                }
                System.out.print((char) ret);
            }
            System.out.println();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述

2.一个参数版本 read(char[] charBuffer)

 public static void main(String[] args) {
        char[] charBuffer = new char[1024];

        try (Reader reader = new FileReader("D:/czy.txt");){
            int ret = 0;
            while (true) {
                ret = reader.read(charBuffer);
                if(ret == -1) {
                    break;
                }
                for (int i = 0; i < ret; i++) {
                    System.out.print(charBuffer[i]);
                }
                System.out.println();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述

4.2.2.2 write

czy.txt文件中原内容为:
在这里插入图片描述

    public static void main(String[] args) {
        try (Writer writer = new FileWriter("D:/czy.txt");){
            writer.write("你在干什么呢?");
            writer.write("hello student!!");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

写完后的内容。写之前会删除原来内容。
在这里插入图片描述


上述这些类的使用方法非常固定。核心就四个操作。

1.打开文件(构造对象)
2.关闭文件。(close)
3.读文件,针对InputStream/Reader
4.写文件,针对OutputStream/Writer

注意!! InputStream、OutputStream、Reader、Writer都是抽象类。不能直接实例化new。

public abstract class InputStream implements Closeable
public abstract class OutputStream implements Closeable, Flushable
public abstract class Reader implements Readable, Closeable
public abstract class Writer implements Appendable, Closeable, Flushable

4.3 Scanner 搭配流对象

Scanner 可以搭配流对象来使用,从硬盘上获取数据。

    public static void main(String[] args) throws IOException {
        try (Reader reader = new FileReader("D:/czy.txt");){
        	// 将流对象传入 Scanner 中
            Scanner scanner = new Scanner(reader);

            while (scanner.hasNext()) {
                String ret = scanner.next();
                System.out.println(ret);
            }
        }
    }

注意!! scanner 这里的close本质上也是要关闭的。但是 Scanner 内部包含了流对象reader,流对象在try运行结束时关闭了,所以scanner 的close 不关闭也没事。


五、总结

有关文件操作IO相关知识就说到这,有喜欢小编的小伙伴们,不妨点点关注,小编也会再接再厉,谢谢大家的支持!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值